# Tests todo:
# - inout with varyings, attributes, uniforms (and arrays of 'em)
# - inout with arrays, array elements
# - inout with array elements
# - inout by-value semantics (arrays & elements & structs)

# Done:
# - control flow: return, return in loop, etc.

group datatypes "Function Parameter Data Types"

    case float_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                return -a;
            }

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case float_vec2
        version 310 es
        values
        {
            input vec2 in0 = [ vec2(0.0, 1.0) | vec2(2.0, 2.5) ];
            output float out0 = [ -1.0 | -4.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (vec2 a)
            {
                return -(a.x + a.y);
            }

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case float_vec3
        version 310 es
        values
        {
            input vec3 in0 = [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
            output float out0 = [ 1.0 | -0.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (vec3 a)
            {
                return -(a.x + a.y + a.z);
            }

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case float_vec4
        version 310 es
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, -2.0, 0.5) | vec4(2.0, 2.5, 4.0, -7.0) ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (vec4 a)
            {
                return -(a.x + a.y + a.z + a.w);
            }

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case float_mat2
        version 310 es
        values
        {
            input mat2 in0 = [ mat2(0.0, 1.0, -2.0, 0.5) | mat2(2.0, 2.5, 4.0, -7.0) ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (mat2 a)
            {
                return -(a[0][0] + a[0][1] + a[1][0] + a[1][1]);
            }

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case float_mat3
        version 310 es
        values
        {
            input mat3 in0 = [ mat3(0.0, 1.0, -2.0, 0.5, 1.0, -1.0, 2.0, 4.0, -1.0) | mat3(2.0, 2.5, 4.0, -7.0, 2.5, 3.0, 0.5, -3.5, 1.0) ];
            output float out0 = [ -4.5 | -5.0 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (mat3 a)
            {
                return -(a[0][0] + a[0][1] + a[0][2] + a[1][0] + a[1][1] + a[1][2] + a[2][0] + a[2][1] + a[2][2]);
            }

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case float_mat4
        version 310 es
        values
        {
            input mat4 in0 = [ mat4(0.0, 1.0, -2.0, 0.5, 1.0, -1.0, 2.0, 4.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -2.0, -2.0) | mat4(2.0, 2.5, 4.0, -7.0, 2.5, 3.0, 0.5, -3.5, 1.0, 0.0, 2.0, -1.0, 1.0, 0.0, -1.0, 3.0) ];
            output float out0 = [ -5.5 | -9.0 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (mat4 a)
            {
                return -(a[0][0] + a[0][1] + a[0][2] + a[0][3] + a[1][0] + a[1][1] + a[1][2] + a[1][3] + a[2][0] + a[2][1] + a[2][2] + a[2][3] + a[3][0] + a[3][1] + a[3][2] + a[3][3]);
            }

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case int_int
        version 310 es
        values
        {
            input int in0 = [ -1 | 0 | 1 | 4 ];
            output int out0 = [ 1 | 0 | -1 | -4 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (int a)
            {
                return -a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case int_ivec2
        version 310 es
        values
        {
            input ivec2 in0 = [ ivec2(-1, 0) | ivec2(1, 4) ];
            output int out0 = [ 1 | -5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (ivec2 a)
            {
                return -(a.x + a.y);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case int_ivec3
        version 310 es
        values
        {
            input ivec3 in0 = [ ivec3(-1, 0, 2) | ivec3(1, 4, -8) ];
            output int out0 = [ -1 | 3 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (ivec3 a)
            {
                return -(a.x + a.y + a.z);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case int_ivec4
        version 310 es
        values
        {
            input ivec4 in0 = [ ivec4(-1, 0, 2, 2) | ivec4(1, 4, -8, 2) ];
            output int out0 = [ -3 | 1 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (ivec4 a)
            {
                return -(a.x + a.y + a.z + a.w);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case uint_uint
        version 310 es
        values
        {
            input uint in0 = [ 1 | 0 | 2 | 4 ];
            output uint out0 = [ 1 | 0 | 4 | 16 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            uint func (uint a)
            {
                return a*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case uint_uvec2
        version 310 es
        values
        {
            input uvec2 in0 = [ uvec2(1, 0) | uvec2(2, 4) ];
            output uint out0 = [ 1 | 6 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            uint func (uvec2 a)
            {
                return (a.x + a.y);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case uint_uvec3
        version 310 es
        values
        {
            input uvec3 in0 = [ uvec3(1, 0, 2) | uvec3(1, 4, 8) ];
            output uint out0 = [ 3 | 13 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            uint func (uvec3 a)
            {
                return (a.x + a.y + a.z);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case uint_uvec4
        version 310 es
        values
        {
            input uvec4 in0 = [ uvec4(1, 0, 2, 2) | uvec4(1, 4, 8, 2) ];
            output uint out0 = [ 5 | 15 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            uint func (uvec4 a)
            {
                return (a.x + a.y + a.z + a.w);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case bool_bool
        version 310 es
        values
        {
            input bool in0 = [ true | false ];
            output bool out0 = [ false | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (bool a)
            {
                return !a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case bool_bvec2
        version 310 es
        values
        {
            input bvec2 in0 = [ bvec2(true, true) | bvec2(false, true) ];
            output bool out0 = [ false | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (bvec2 a)
            {
                return !(a.x == a.y);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case bool_bvec3
        version 310 es
        values
        {
            input bvec3 in0 = [ bvec3(true, true, false) | bvec3(true, false, false) ];
            output bool out0 = [ false | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (bvec3 a)
            {
                return (a.x == a.y) == a.z;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case bool_bvec4
        version 310 es
        values
        {
            input bvec4 in0 = [ bvec4(true, true, true, false) | bvec4(false, false, true, true) | bvec4(true, false, false, true) ];
            output bool out0 = [ false | true | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (bvec4 a)
            {
                return ((a.x == a.y) == (a.z == a.w));
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case mat2
        version 310 es
        values
        {
            input mat2 in0 = [ mat2(-2.0, 0.5, -1.0, 1.0) | mat2(1.0, -3.5, -3.5, 2.5) | mat2(-2.0, -2.0, 3.5, 0.0) ];
            output mat2 out0 = [ mat2(4.0, -1.0, 2.0, -2.0) | mat2(-2.0, 7.0, 7.0, -5.0) | mat2(4.0, 4.0, -7.0, -0.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat2 func (mat2 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end


    case mat2x3
        version 310 es
        values
        {
            input mat2x3 in0 = [ mat2x3(2.5, 0.0, 1.0, -2.5, 1.0, 3.0) | mat2x3(0.0, 2.0, 1.5, -3.5, 2.0, 0.5) | mat2x3(-1.5, -3.5, 2.5, 0.0, 1.5, 3.0) ];
            output mat2x3 out0 = [ mat2x3(-5.0, -0.0, -2.0, 5.0, -2.0, -6.0) | mat2x3(-0.0, -4.0, -3.0, 7.0, -4.0, -1.0) | mat2x3(3.0, 7.0, -5.0, -0.0, -3.0, -6.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat2x3 func (mat2x3 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end


    case mat2x4
        version 310 es
        values
        {
            input mat2x4 in0 = [ mat2x4(1.5, 3.0, -1.0, 2.5, -0.5, 3.5, 3.0, -3.0) | mat2x4(-2.5, -2.0, 3.5, -0.5, 1.0, -1.5, 0.0, -1.0) | mat2x4(-1.0, 0.5, 0.5, 3.0, 1.5, 3.0, 2.5, 3.5) ];
            output mat2x4 out0 = [ mat2x4(-3.0, -6.0, 2.0, -5.0, 1.0, -7.0, -6.0, 6.0) | mat2x4(5.0, 4.0, -7.0, 1.0, -2.0, 3.0, -0.0, 2.0) | mat2x4(2.0, -1.0, -1.0, -6.0, -3.0, -6.0, -5.0, -7.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat2x4 func (mat2x4 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end


    case mat3x2
        version 310 es
        values
        {
            input mat3x2 in0 = [ mat3x2(1.5, -2.5, 2.5, 3.5, 3.0, 0.5) | mat3x2(1.5, -2.0, 2.5, 0.5, -1.5, -3.5) | mat3x2(2.5, 3.5, -3.0, 2.5, -0.5, -2.5) ];
            output mat3x2 out0 = [ mat3x2(-3.0, 5.0, -5.0, -7.0, -6.0, -1.0) | mat3x2(-3.0, 4.0, -5.0, -1.0, 3.0, 7.0) | mat3x2(-5.0, -7.0, 6.0, -5.0, 1.0, 5.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat3x2 func (mat3x2 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end


    case mat3
        version 310 es
        values
        {
            input mat3 in0 = [ mat3(-1.5, 2.0, 3.0, -3.5, 1.0, -3.5, 1.5, -1.5, 3.0) | mat3(3.5, 0.0, 3.5, -1.5, -3.0, 0.5, -3.5, -2.5, -0.5) | mat3(1.0, -2.5, -3.5, 3.0, -1.5, 3.5, 3.0, -1.0, -0.5) ];
            output mat3 out0 = [ mat3(3.0, -4.0, -6.0, 7.0, -2.0, 7.0, -3.0, 3.0, -6.0) | mat3(-7.0, -0.0, -7.0, 3.0, 6.0, -1.0, 7.0, 5.0, 1.0) | mat3(-2.0, 5.0, 7.0, -6.0, 3.0, -7.0, -6.0, 2.0, 1.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat3 func (mat3 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end


    case mat3x4
        version 310 es
        values
        {
            input mat3x4 in0 = [ mat3x4(0.0, 1.0, 0.5, 0.5, 1.0, 3.5, 0.0, -0.5, 1.5, -2.0, -1.5, 3.5) | mat3x4(0.0, 0.5, -3.5, -0.5, 0.5, -3.5, 1.0, 1.0, -3.5, 1.0, -0.5, 1.5) | mat3x4(-1.0, 1.5, 2.0, -3.5, -3.5, 1.5, 3.5, -2.0, -0.5, 0.5, -1.5, -1.0) ];
            output mat3x4 out0 = [ mat3x4(-0.0, -2.0, -1.0, -1.0, -2.0, -7.0, -0.0, 1.0, -3.0, 4.0, 3.0, -7.0) | mat3x4(-0.0, -1.0, 7.0, 1.0, -1.0, 7.0, -2.0, -2.0, 7.0, -2.0, 1.0, -3.0) | mat3x4(2.0, -3.0, -4.0, 7.0, 7.0, -3.0, -7.0, 4.0, 1.0, -1.0, 3.0, 2.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat3x4 func (mat3x4 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end


    case mat4x2
        version 310 es
        values
        {
            input mat4x2 in0 = [ mat4x2(-1.5, -1.0, 0.5, -1.5, -1.0, 2.0, -3.5, 0.5) | mat4x2(2.0, -1.5, -2.0, 2.5, -2.0, -2.5, -0.5, 1.5) | mat4x2(-3.0, -1.5, -1.0, 2.5, -0.5, 2.5, -2.5, -1.0) ];
            output mat4x2 out0 = [ mat4x2(3.0, 2.0, -1.0, 3.0, 2.0, -4.0, 7.0, -1.0) | mat4x2(-4.0, 3.0, 4.0, -5.0, 4.0, 5.0, 1.0, -3.0) | mat4x2(6.0, 3.0, 2.0, -5.0, 1.0, -5.0, 5.0, 2.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat4x2 func (mat4x2 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end


    case mat4x3
        version 310 es
        values
        {
            input mat4x3 in0 = [ mat4x3(1.0, 3.0, -0.5, -2.0, -3.0, 0.0, -2.5, 2.5, 2.5, -2.5, -1.5, 2.5) | mat4x3(1.0, 2.5, -1.0, -3.0, -1.5, 2.0, -1.5, -1.0, -0.5, -0.5, -0.5, 3.0) | mat4x3(-2.5, -3.5, 3.5, 3.0, 3.5, -0.5, 3.5, 3.0, -2.0, 2.0, 2.5, 1.0) ];
            output mat4x3 out0 = [ mat4x3(-2.0, -6.0, 1.0, 4.0, 6.0, -0.0, 5.0, -5.0, -5.0, 5.0, 3.0, -5.0) | mat4x3(-2.0, -5.0, 2.0, 6.0, 3.0, -4.0, 3.0, 2.0, 1.0, 1.0, 1.0, -6.0) | mat4x3(5.0, 7.0, -7.0, -6.0, -7.0, 1.0, -7.0, -6.0, 4.0, -4.0, -5.0, -2.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat4x3 func (mat4x3 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end


    case mat4
        version 310 es
        values
        {
            input mat4 in0 = [ mat4(0.0, -1.5, -1.0, -2.0, -3.0, 0.5, -1.5, 2.5, -3.5, 3.0, 1.5, 3.0, 3.0, 3.0, 0.5, -3.5) | mat4(2.0, -2.5, -1.5, 1.0, 0.0, -0.5, 3.5, 1.0, -1.0, -2.0, 2.5, 0.0, 2.0, -1.0, -2.5, 0.5) | mat4(2.5, -2.5, 2.0, 3.0, 2.5, 2.5, -3.5, 1.0, 2.5, -3.5, -1.5, -1.5, 0.0, -0.5, 0.0, 2.0) ];
            output mat4 out0 = [ mat4(-0.0, 3.0, 2.0, 4.0, 6.0, -1.0, 3.0, -5.0, 7.0, -6.0, -3.0, -6.0, -6.0, -6.0, -1.0, 7.0) | mat4(-4.0, 5.0, 3.0, -2.0, -0.0, 1.0, -7.0, -2.0, 2.0, 4.0, -5.0, -0.0, -4.0, 2.0, 5.0, -1.0) | mat4(-5.0, 5.0, -4.0, -6.0, -5.0, -5.0, 7.0, -2.0, -5.0, 7.0, 3.0, 3.0, -0.0, 1.0, -0.0, -4.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            mat4 func (mat4 a)
            {
                return -2.0*a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case float_struct
        version 310 es
        values
        {
            input vec3 in0 = [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
            output float out0 = [ 1.0 | -0.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            struct Pos { float a, b, c; };

            float func (Pos p)
            {
                return -(p.a + p.b + p.c);
            }

            void main()
            {
                Pos p = Pos(in0.x, in0.y, in0.z);
                out0 = func(p);
                ${OUTPUT}
            }
        ""
    end

    case struct_struct
        version 310 es
        values
        {
            input vec3 in0 = [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
            output float out0 = [ 1.0 | -0.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            struct Pos { float a, b, c; };

            Pos func (Pos p)
            {
                return Pos(-p.a, -p.b, -p.c);
            }

            void main()
            {
                Pos p = Pos(in0.x, in0.y, in0.z);
                p = func(p);
                out0 = p.a + p.b + p.c;
                ${OUTPUT}
            }
        ""
    end

    case struct_nested_struct
        version 310 es
        values
        {
            input vec3 in0 = [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
            output float out0 = [ 1.0 | -0.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            struct Pos { float a, b, c; };
            struct Line { Pos start, end; };

            Line func (Pos p)
            {
                return Line(p, Pos(-p.a, -p.b, -p.c));
            }

            float sum (Pos p)
            {
                return (p.a + p.b + p.c);
            }

            void main()
            {
                Pos p = Pos(in0.x, in0.y, in0.z);
                Line line = func(p);
                out0 = sum(line.start) + (2.0 * sum(line.end));
                ${OUTPUT}
            }
        ""
    end


end # datatypes

group qualifiers "Function Parameter Qualifiers"

    case in_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            float func (in float a)
            {
                a = -a;
                return 2.0 * a;
            }

            void main()
            {
                ${SETUP}
                float f = in0;
                float g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case out_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (out float a)
            {
                a = -1.0;
            }

            void main()
            {
                ${SETUP}
                float f = 1.0;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case inout_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (inout float a)
            {
                a = -a;
            }

            void main()
            {
                ${SETUP}
                float f = 1.0;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case in_lowp_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            float func (in lowp float a)
            {
                a = -a;
                return 2.0 * a;
            }

            void main()
            {
                ${SETUP}
                float f = in0;
                float g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case out_lowp_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (out lowp float a)
            {
                a = -1.0;
            }

            void main()
            {
                ${SETUP}
                float f = 1.0;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case inout_lowp_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (inout lowp float a)
            {
                a = -a;
            }

            void main()
            {
                ${SETUP}
                float f = 1.0;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case in_highp_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            float func (in highp float a)
            {
                a = -a;
                return 2.0 * a;
            }

            void main()
            {
                ${SETUP}
                float f = in0;
                float g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case out_highp_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (out highp float a)
            {
                a = -1.0;
            }

            void main()
            {
                ${SETUP}
                float f = 1.0;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case inout_highp_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (inout highp float a)
            {
                a = -a;
            }

            void main()
            {
                ${SETUP}
                float f = 1.0;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case const_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            float func (const float a)
            {
                float b = -a;
                return 2.0 * b;
            }

            void main()
            {
                ${SETUP}
                float f = in0;
                float g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case const_in_float
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            float func (const in float a)
            {
                float b = -a;
                return 2.0 * b;
            }

            void main()
            {
                ${SETUP}
                float f = in0;
                float g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case in_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 4 ];
            output int out0 = [ 0 | -1 | 2 | -4 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (in int a)
            {
                a = -a;
                return 2 * a;
            }

            void main()
            {
                ${SETUP}
                int f = in0;
                int g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case out_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 6 ];
            output int out0 = [ 0 | -1 | 2 | -6 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (out int a)
            {
                a = -1;
            }

            void main()
            {
                ${SETUP}
                int f = 1;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case inout_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 6 ];
            output int out0 = [ 0 | -1 | 2 | -6 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (inout int a)
            {
                a = -a;
            }

            void main()
            {
                ${SETUP}
                int f = 1;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case in_lowp_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 4 ];
            output int out0 = [ 0 | -1 | 2 | -4 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (in lowp int a)
            {
                a = -a;
                return 2 * a;
            }

            void main()
            {
                ${SETUP}
                int f = in0;
                int g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case out_lowp_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 6 ];
            output int out0 = [ 0 | -1 | 2 | -6 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (out lowp int a)
            {
                a = -1;
            }

            void main()
            {
                ${SETUP}
                int f = 1;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case inout_lowp_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 6 ];
            output int out0 = [ 0 | -1 | 2 | -6 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (inout lowp int a)
            {
                a = -a;
            }

            void main()
            {
                ${SETUP}
                int f = 1;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case in_highp_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 4 ];
            output int out0 = [ 0 | -1 | 2 | -4 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (in highp int a)
            {
                a = -a;
                return 2 * a;
            }

            void main()
            {
                ${SETUP}
                int f = in0;
                int g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case out_highp_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 6 ];
            output int out0 = [ 0 | -1 | 2 | -6 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (out highp int a)
            {
                a = -1;
            }

            void main()
            {
                ${SETUP}
                int f = 1;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case inout_highp_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 6 ];
            output int out0 = [ 0 | -1 | 2 | -6 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (inout highp int a)
            {
                a = -a;
            }

            void main()
            {
                ${SETUP}
                int f = 1;
                func(f);
                out0 = f * in0;
                ${OUTPUT}
            }
        ""
    end

    case const_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 4 ];
            output int out0 = [ 0 | -1 | 2 | -4 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (const int a)
            {
                int b = -a;
                return 2 * b;
            }

            void main()
            {
                ${SETUP}
                int f = in0;
                int g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case const_in_int
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 4 ];
            output int out0 = [ 0 | -1 | 2 | -4 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (const in int a)
            {
                int b = -a;
                return 2 * b;
            }

            void main()
            {
                ${SETUP}
                int f = in0;
                int g = func(f);
                out0 = f + g;
                ${OUTPUT}
            }
        ""
    end

    case in_bool
        version 310 es
        values
        {
            input bool in0 = [ true | false ];
            output bool out0 = [ true | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (in bool a)
            {
                a = !a;
                return a;
            }

            void main()
            {
                ${SETUP}
                bool f = in0;
                bool g = func(f);
                out0 = (f != g);
                ${OUTPUT}
            }
        ""
    end

    case out_bool
        version 310 es
        values
        {
            input bool in0 = [ true | false ];
            output bool out0 = [ false | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (out bool a)
            {
                a = false;
            }

            void main()
            {
                ${SETUP}
                bool f = true;
                func(f);
                out0 = (in0 == f);
                ${OUTPUT}
            }
        ""
    end

    case inout_bool
        version 310 es
        values
        {
            input bool in0 = [ true | false ];
            output bool out0 = [ false | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            void func (inout bool a)
            {
                a = !a;
            }

            void main()
            {
                ${SETUP}
                bool f = true;
                func(f);
                out0 = (in0 == f);
                ${OUTPUT}
            }
        ""
    end

    case const_bool
        version 310 es
        values
        {
            input bool in0 = [ true | false ];
            output bool out0 = [ true | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (const bool a)
            {
                bool b = !a;
                return b;
            }

            void main()
            {
                ${SETUP}
                bool f = in0;
                bool g = func(f);
                out0 = (f != g);
                ${OUTPUT}
            }
        ""
    end

end # qualifiers

group declarations "Function Declarations"

    case basic
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (void);

            float func (void)
            {
                return -1.0;
            }

            void main()
            {
                out0 = func() * in0;
                ${OUTPUT}
            }
        ""
    end

    case basic_arg
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float f);

            float func (float f)
            {
                return -f;
            }

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case define_after_use
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (void);

            void main()
            {
                out0 = func() * in0;
                ${OUTPUT}
            }

            float func (void)
            {
                return -1.0;
            }
        ""
    end

    case double_declare
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (void);

            float func (void);

            float func (void)
            {
                return -1.0;
            }

            void main()
            {
                out0 = func() * in0;
                ${OUTPUT}
            }
        ""
    end

    case declare_after_define
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (void)
            {
                return -1.0;
            }

            float func (void);

            void main()
            {
                out0 = func() * in0;
                ${OUTPUT}
            }
        ""
    end

    case void_vs_no_void
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func ();

            void main()
            {
                out0 = func() * in0;
                ${OUTPUT}
            }

            float func (void)
            {
                return -1.0;
            }
        ""
    end

    case in_vs_no_in
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float f);

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }

            float func (in float f)
            {
                return -f;
            }
        ""
    end

    case default_vs_explicit_precision
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            precision mediump float;

            float func (float f);

            precision highp float;

            void main()
            {
                out0 = func(in0);
                ${OUTPUT}
            }

            float func (mediump float f)
            {
                return -f;
            }
        ""
    end


end # declarations

group overloading "Function Overloading"

    case user_func_arg_type_simple
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            float func (float a)
            {
                return -a;
            }

            int func (int a)
            {
                return -a;
            }

            void main()
            {
                out0 = func(in0) * float(func(-1));
                ${OUTPUT}
            }
        ""
    end

    case user_func_arg_float_types
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            float func (float a) { return -a; }
            vec2 func (vec2 a) { return a.yx; }
            vec3 func (vec3 a) { return a.xxx; }
            vec4 func (vec4 a) { return a.wwww; }

            void main()
            {
                out0 = func(func(func(func(vec4(in0)).xyz).xy).x);
                ${OUTPUT}
            }
        ""
    end

    case user_func_arg_int_types
        version 310 es
        values
        {
            input int in0 = [ 0 | 1 | -2 | 6 ];
            output int out0 = [ 0 | -1 | 2 | -6 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (int a) { return -a; }
            ivec2 func (ivec2 a) { return a.yx; }
            ivec3 func (ivec3 a) { return a.xxx; }
            ivec4 func (ivec4 a) { return a.wwww; }

            void main()
            {
                ${SETUP}
                out0 = func(func(func(func(ivec4(in0)).xyz).xy).x);
                ${OUTPUT}
            }
        ""
    end

    case user_func_arg_bool_types
        version 310 es
        values
        {
            input bool in0 = [ true | false ];
            output bool out0 = [ false | true ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (bool a) { return !a; }
            bvec2 func (bvec2 a) { return a.yx; }
            bvec3 func (bvec3 a) { return a.xxx; }
            bvec4 func (bvec4 a) { return a.wwww; }

            void main()
            {
                ${SETUP}
                out0 = func(func(func(func(bvec4(in0)).xyz).xy).x);
                ${OUTPUT}
            }
        ""
    end

    case user_func_arg_basic_types
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            float func (float a) { return -a; }
            vec2 func (vec2 a) { return a.yx; }
            vec3 func (vec3 a) { return a.xxx; }
            vec4 func (vec4 a) { return a.wwww; }
            int func (int a) { return -a; }
            ivec2 func (ivec2 a) { return a.yx; }
            ivec3 func (ivec3 a) { return a.xxx; }
            ivec4 func (ivec4 a) { return a.wwww; }
            bool func (bool a) { return !a; }
            bvec2 func (bvec2 a) { return a.yx; }
            bvec3 func (bvec3 a) { return a.xxx; }
            bvec4 func (bvec4 a) { return a.wwww; }

            void main()
            {
                ${SETUP}
                if (func(func(bvec4(false)).x))
                    out0 = func(in0) * float(func(-1));
                else
                    out0 = float(func(func(ivec4(func(func(func(vec4(0.5)).xyz).xy).xxxx)).xy).x);
                ${OUTPUT}
            }
        ""
    end

    case user_func_arg_complex_types
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            struct Pos { float a, b, c; };
            struct Line { Pos start, end; };

            float func (float a) { return -a; }
            float func (float a[4]) { return a[0] + a[3]; }
            vec2 func (vec2 a) { return a.yx; }
            vec3 func (vec3 a) { return a.xxx; }
            vec4 func (vec4 a) { return a.wwww; }
            vec4 func (vec4 a[4]) { return a[1] + a[2]; }
            int func (int a) { return -a; }
            ivec2 func (ivec2 a) { return a.yx; }
            ivec3 func (ivec3 a) { return a.xxx; }
            ivec4 func (ivec4 a) { return a.wwww; }
            bool func (bool a) { return !a; }
            bvec2 func (bvec2 a) { return a.yx; }
            bvec3 func (bvec3 a) { return a.xxx; }
            bvec4 func (bvec4 a) { return a.wwww; }
            Pos func (Pos a) { return a; }
            Line func (Line a) { return Line(a.end, a.start); }

            void main()
            {
                ${SETUP}
                float arr[4];
                vec4 arr2[4];
                out0 = func(arr) + func(arr2).x;
                if (func(func(bvec4(false)).x))
                    out0 = func(in0) * float(func(-1));
                else
                    out0 = float(func(func(ivec4(func(func(func(vec4(0.5)).xyz).xy).xxxx)).xy).x);
                ${OUTPUT}
            }
        ""
    end

    case user_func_arguments
        version 310 es
        values
        {
            input float in0 = [ 0.0 | 1.0 | -2.0 | 2.5 ];
            output float out0 = [ 0.0 | -1.0 | 2.0 | -2.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                return -a;
            }

            float func (float a, float b)
            {
                return a * b;
            }

            void main()
            {
                out0 = func(in0) * func(-0.5, -2.0);
                ${OUTPUT}
            }
        ""
    end

    case array_size
        version 310 es
        values
        {
            output float out0 = [ 1.0 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float f[3])
            {
                return f[0];
            }

            float func (float f[4])
            {
                return f[1];
            }

            void main ()
            {
                ${SETUP}
                float[4] x = float[4] (-1.0, 1.0, 0.0, 0.0);
                out0 = func(x);
                ${OUTPUT}
            }
        ""
    end

end # overloading

group array_arguments "Arrays as Arguments"

    case local_in_float
        version 310 es
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
            output vec4 out0 = [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (in float a[4])
            {
                a[0] = -1.0;
                a[2] = -4.0;
                a[3] = -3.0 * a[1];
                return a[0];
            }

            void main()
            {
                float arr[4];
                arr[0] = in0.x;
                arr[1] = in0.y;
                arr[2] = in0.z;
                arr[3] = in0.w;
                float f = func(arr);
                out0 = f * vec4(arr[0], arr[1], arr[2], arr[3]);
                ${OUTPUT}
            }
        ""
    end

    case global_in_float
        version 310 es
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
            output vec4 out0 = [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (in float a[4])
            {
                a[0] = -1.0;
                a[2] = -4.0;
                a[3] = -3.0 * a[1];
                return a[0];
            }

            float arr[4];

            void main()
            {
                arr[0] = in0.x;
                arr[1] = in0.y;
                arr[2] = in0.z;
                arr[3] = in0.w;
                float f = func(arr);
                out0 = f * vec4(arr[0], arr[1], arr[2], arr[3]);
                ${OUTPUT}
            }
        ""
    end

    case local_in_int
        version 310 es
        values
        {
            input ivec4 in0 = [ ivec4(0, 1, 2, -4) | ivec4(-7, -11, 13, 19) ];
            output ivec4 out0 = [ ivec4(0, -1, -2, 4) | ivec4(7, 11, -13, -19) ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (in int a[4])
            {
                a[0] = -1;
                a[2] = -4;
                a[3] = -3 * a[1];
                return a[0];
            }

            void main()
            {
                ${SETUP}
                int arr[4];
                arr[0] = in0.x;
                arr[1] = in0.y;
                arr[2] = in0.z;
                arr[3] = in0.w;
                int f = func(arr);
                out0 = f * ivec4(arr[0], arr[1], arr[2], arr[3]);
                ${OUTPUT}
            }
        ""
    end

    case global_in_int
        version 310 es
        values
        {
            input ivec4 in0 = [ ivec4(0, 1, 2, 4) | ivec4(-7, -11, 13, 19) ];
            output ivec4 out0 = [ ivec4(0, -1, -2, -4) | ivec4(7, 11, -13, -19) ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (in int a[4])
            {
                a[0] = -1;
                a[2] = -4;
                a[3] = -3 * a[1];
                return a[0];
            }

            int arr[4];

            void main()
            {
                ${SETUP}
                arr[0] = in0.x;
                arr[1] = in0.y;
                arr[2] = in0.z;
                arr[3] = in0.w;
                int f = func(arr);
                out0 = f * ivec4(arr[0], arr[1], arr[2], arr[3]);
                ${OUTPUT}
            }

        ""
    end

    case local_in_bool
        version 310 es
        values
        {
            input bvec4 in0 = [ bvec4(true, true, false, true) | bvec4(false, false, false, false) ];
            output bvec4 out0 = [ bvec4(false, false, true, false) | bvec4(true, true, true, true) ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (in bool a[4])
            {
                a[0] = false;
                a[2] = true;
                a[3] = !a[1];
                return a[0];
            }

            void main()
            {
                ${SETUP}
                bool arr[4];
                arr[0] = !in0.x;
                arr[1] = !in0.y;
                arr[2] = !in0.z;
                arr[3] = !in0.w;
                func(arr);
                out0 = bvec4(arr[0], arr[1], arr[2], arr[3]);
                ${OUTPUT}
            }
        ""
    end

    case global_in_bool
        version 310 es
        values
        {
            input bvec4 in0 = [ bvec4(true, true, false, true) | bvec4(false, false, false, false) ];
            output bvec4 out0 = [ bvec4(false, false, true, false) | bvec4(true, true, true, true) ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            bool func (in bool a[4])
            {
                a[0] = false;
                a[2] = true;
                a[3] = !a[1];
                return a[0];
            }

            bool arr[4];

            void main()
            {
                ${SETUP}
                arr[0] = !in0.x;
                arr[1] = !in0.y;
                arr[2] = !in0.z;
                arr[3] = !in0.w;
                func(arr);
                out0 = bvec4(arr[0], arr[1], arr[2], arr[3]);
                ${OUTPUT}
            }
        ""
    end

    case test_helpers
        version 310 es
        desc "Check that helper functions are supported properly."
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
            output float out0 = [ 1.0 | 1.0 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            vec4 get (in float arr[4]);
            void set (out float arr[4], vec4 val);
            void negate (inout float arr[4]);
            bool test (in float arr[4], vec4 ref);
            bool isEqual (in float a[4], in float b[4]);

            void main()
            {
                float arr[4];
                set(arr, in0);
                negate(arr);
                out0 = float(test(arr, -in0));
                ${OUTPUT}
            }

            float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
            vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
            void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
            void negate (inout float arr[4]) { set(arr, -get(arr)); }
            bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
            bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
        ""
    end

    case copy_local_in_on_call
        version 310 es
        desc "Check that local 'in' arguments are copied on call and don't alias."
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
            output vec4 out0 = [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            vec4 get (in float arr[4]);
            void set (out float arr[4], vec4 val);
            void negate (inout float arr[4]);
            bool test (in float arr[4], vec4 ref);
            bool isEqual (in float a[4], in float b[4]);

            float func (in float a[4], in float b[4])
            {
                a[0] = 2.123;
                a[2] = -4.123;
                return isEqual(a, b) ? 1.0 : -1.0;
            }

            void main()
            {
                float arr[4];
                set(arr, in0);
                out0 = in0 * func(arr, arr);
                ${OUTPUT}
            }

            float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
            vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
            void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
            void negate (inout float arr[4]) { set(arr, -get(arr)); }
            bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
            bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
        ""
    end

    case copy_global_in_on_call
        version 310 es
        desc "Check that global 'in' arguments are copied on call and don't alias."
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
            output vec4 out0 = [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            vec4 get (in float arr[4]);
            void set (out float arr[4], vec4 val);
            void negate (inout float arr[4]);
            bool test (in float arr[4], vec4 ref);
            bool isEqual (in float a[4], in float b[4]);

            float func (in float a[4], in float b[4])
            {
                a[0] = 2.123;
                a[2] = -4.123;
                return isEqual(a, b) ? 1.0 : -1.0;
            }

            float arr[4];

            void main()
            {
                set(arr, in0);
                out0 = in0 * func(arr, arr);
                ${OUTPUT}
            }

            float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
            vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
            void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
            void negate (inout float arr[4]) { set(arr, -get(arr)); }
            bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
            bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
        ""
    end

    case copy_local_inout_on_call
        version 310 es
        desc "Check that local 'in' arguments are copied on call and don't alias."
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
            output vec4 out0 = [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            vec4 get (in float arr[4]);
            void set (out float arr[4], vec4 val);
            void negate (inout float arr[4]);
            bool test (in float arr[4], vec4 ref);
            bool isEqual (in float a[4], in float b[4]);

            float func (inout float a[4], inout float b[4])
            {
                negate(a);
                return isEqual(a, b) ? 1.0 : -1.0;
            }

            void main()
            {
                float arr[4];
                set(arr, in0);
                float m = func(arr, arr); // returns -1.0
                float n = float(test(arr, in0) || test(arr, -in0));
                out0 = in0 * m * n;
                ${OUTPUT}
            }

            float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
            vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
            void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
            void negate (inout float arr[4]) { set(arr, -get(arr)); }
            bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
            bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
        ""
    end

    case copy_global_inout_on_call
        version 310 es
        desc "Check that global 'in' arguments are copied on call and don't alias."
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
            output vec4 out0 = [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            vec4 get (in float arr[4]);
            void set (out float arr[4], vec4 val);
            void negate (inout float arr[4]);
            bool test (in float arr[4], vec4 ref);
            bool isEqual (in float a[4], in float b[4]);

            float func (in float a[4], in float b[4])
            {
                negate(a);
                return isEqual(a, b) ? 1.0 : -1.0;
            }

            float arr[4];

            void main()
            {
                set(arr, in0);
                float m = func(arr, arr); // returns -1.0
                float n = float(test(arr, in0) || test(arr, -in0));
                out0 = in0 * m * n;
                ${OUTPUT}
            }

            float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
            vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
            void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
            void negate (inout float arr[4]) { set(arr, -get(arr)); }
            bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
            bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
        ""
    end

#            vec4 get (in float arr[4]);
#            void set (out float arr[4], vec4 val);
#            void negate (inout float arr[4]);
#            bool test (in float arr[4], vec4 ref);
#            bool isEqual (in float a[4], in float b[4]);

#            float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
#            vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
#            void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
#            void negate (inout float arr[4]) { set(arr, -get(arr)); }
#            bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
#            bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }

end # array_arguments

#group qualifiers "Function Parameter Qualifiers"
#
#end # qualifiers

group control_flow "Control Flow In Functions"

    case simple_return
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                return -a;
                a = a * -1.0;
                return 1.0;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_in_if
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                if (a != 0.0)
                    return -a;
                return 1.0;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_in_else
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                if (a == 0.0)
                    return 1.0;
                else
                    return -a;
                return 1.0;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_in_loop
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                while (a < 100.0)
                    return -a;
                return 1.0;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_in_loop_if
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                while (a < 100.0)
                {
                    a = -a;
                    if (a != 0.0)
                        return a;
                    else
                        return -1.0;
                }
                return 1.0;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_after_loop
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                for (int i = 0; i < 5; i++)
                    a = -a;
                return a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_after_break
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                for (int i = 0; i < 6; i++)
                {
                    a = -a;
                    if (i == 4)
                        break;
                }
                return a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_after_continue
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                for (int i = 0; i < 6; i++)
                {
                    if (i == 4)
                        continue;
                    a = -a;
                }
                return a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_in_nested_loop
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                for (int i = 0; i < 6; i++)
                {
                    a = -a;
                    for (int j = 0; j < 4; j++)
                    {
                        a = -a;
                        if (i == 1)
                            return a;
                    }
                    if (i == 4)
                        return 1.0;
                }
                return 1.0;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case return_after_loop_sequence
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                int i;
                for (i = 0; i < 6; i++) // negate a
                {
                    a = -a;
                    if (i == 4)
                        a = -a;
                }

                for (; i < 10; i++) // keep a
                {
                    if (i == 8)
                        continue;
                    else if (i == 9)
                        break;
                    a = -a;
                }

                return a;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

    case mixed_return_break_continue
        version 310 es
        values
        {
            input float in0 = [ -0.5 | 1.5 ];
            output float out0 = [ 0.5 | -1.5 ];
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float func (float a)
            {
                int i;
                for (i = 0; i < 6; i++)
                {
                    if (i == 0)
                        continue;
                    else if (i == 1)
                    {
                    }
                    else if (i == 3)
                        break;
                    else
                        return a;
                    a = -a;
                }

                return 1.0;
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0);
                ${OUTPUT}
            }
        ""
    end

end # control_flow

group misc "Miscellaneous"

    case multi_arg_float
        version 310 es
        values
        {
            input vec4 in0 = [ vec4(0.0, 1.0, -2.0, 0.5) | vec4(2.0, 2.5, 4.0, -7.0) ];
            output float out0 = [ 0.5 | -1.5 ]; # -sum(in0)
        }

        both ""
            #version 310 es
            precision highp float;
            ${DECLARATIONS}

            float sum(vec4 v) { return (v.x + v.y + v.z + v.w); }

            float func (float a, vec3 b, vec2 c, vec2 d, vec4 e)
            {
                return -sum(vec4(a, b) + vec4(c, d)) + sum(e);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0.y, in0.xzw, in0.wz, in0.yx, in0);
                ${OUTPUT}
            }
        ""
    end

    case multi_arg_int
        version 310 es
        values
        {
            input ivec4 in0 = [ ivec4(-1, 0, 2, 2) | ivec4(1, 4, -8, 2) ];
            output int out0 = [ -3 | 1 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int sum(ivec4 v) { return (v.x + v.y + v.z + v.w); }

            int func (int a, ivec3 b, ivec2 c, ivec2 d, ivec4 e)
            {
                return -sum(ivec4(a, b) + ivec4(c, d)) + sum(e);
            }

            void main()
            {
                ${SETUP}
                out0 = func(in0.y, in0.xzw, in0.wz, in0.yx, in0);
                ${OUTPUT}
            }
        ""
    end

    case argument_eval_order_1
        version 310 es
        values
        {
            input int in0 = [  0 | 1 | 3 | 5 ];
            output int out0 = [ -1 | 5 | 11 | 17 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int func (float a, int b, bool c, int d)
            {
                if (c)
                    return b + int(a) + d;
                else
                    return -1;
            }

            void main ()
            {
                ${SETUP}
                float v0 = float(in0);
                int v1 = in0;
                out0 = func((v0 += 1.0), v1++, (v0 > 1.5), v1);
                ${OUTPUT}
            }
        ""
    end

    case argument_eval_order_2
        version 310 es
        values
        {
            input int in0 = [ 0 | -1 | 3 | 5 ];
            output int out0 = [ 3 | -1 | 9 | 13 ];
        }

        both ""
            #version 310 es
            precision highp float;
            precision highp int;
            ${DECLARATIONS}

            int g;

            int modG (int v)
            {
                g += v;
                return v;
            }

            int func (float a, int b, bool c, int d)
            {
                if (c)
                    return b + int(a) + d;
                else
                    return -1;
            }

            void main ()
            {
                ${SETUP}
                out0 = func(float(g = in0), modG(2), --g > 0, g);
                ${OUTPUT}
            }
        ""
    end

end # misc
