Fix flaws in minus-prefix optimization.

We had a logic bug when attempting to optimize the following code:
    const vecN x = vecN(a, b, c);
    -x;

The goal was to replace `-x` with `vecN(-a, -b, -c)` but we accidentally
tried to cast the `x` VariableReference to a Constructor. We
unfortunately didn't cover this in any of our test cases, but the fuzzer
managed to synthesize it by mixing and matching elements from its new
corpus.

This affected several different constructor types: splat, diagonal-
matrix, compound and array.

Change-Id: I10dd2460ab26ba3e820b0cff5db091368fb7e648
Bug: oss-fuzz:37764, oss-fuzz:37861
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/443407
Commit-Queue: John Stiles <johnstiles@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
John Stiles 2021-08-30 15:47:00 -04:00 committed by SkCQ
parent 75bab9249d
commit f89a8122a4
11 changed files with 385 additions and 333 deletions

View File

@ -332,7 +332,7 @@ sksl_shared_tests = [
"/sksl/shared/MatrixScalarSplat.sksl",
"/sksl/shared/MatrixToVectorCast.sksl",
"/sksl/shared/MultipleAssignments.sksl",
"/sksl/shared/NegatedVectorLiteral.sksl",
"/sksl/shared/Negation.sksl",
"/sksl/shared/NoFragCoordsPos.vert",
"/sksl/shared/NoFragCoordsPosRT.vert",
"/sksl/shared/NormalizationVert.vert",

View File

@ -1,31 +0,0 @@
uniform half4 colorGreen, colorRed;
bool test_float() {
const float one = 1;
float two = 2;
float4 result;
result.r = (half4(-1) == -half4(-half2(-1), half2(1))) ? 1 : 0;
result.g = (half4(1) != -half4(1)) ? 1 : 0;
result.b = (-half4(two) == half4(-two, half3(-two))) ? 1 : 0;
result.a = (-half2(-one, one + one) == -half2(one - two, two)) ? 1 : 0;
return bool(result.r * result.g * result.b * -(-result.a));
}
bool test_int() {
int one = 1;
const int two = 2;
int4 result;
result.r = (int4(-1) == -int4(-int2(-1), int2(1))) ? 1 : 0;
result.g = (int4(1) != -int4(1)) ? 1 : 0;
result.b = (-int4(two) == int4(-two, int3(-two))) ? 1 : 0;
result.a = (-int2(-one, one + one) == -int2(one - two, two)) ? 1 : 0;
return bool(-(-result.r) * result.g * result.b * result.a);
}
half4 main(float2 coords) {
return test_float() && test_int() ? colorGreen : colorRed;
}

View File

@ -0,0 +1,67 @@
uniform half4 colorGreen, colorRed;
bool test_fvec() {
const float one = 1;
float two = 2;
const half4 one_splat = half4(1);
const half4 one_compound = half4(1, 1, 1, 1);
bool ok = true;
ok = ok && (half4(-1) == -one_splat);
ok = ok && (half4(-1, -1, -1, -1) == -one_splat);
ok = ok && (half4(-1) == -one_compound);
ok = ok && (half4(-1, -1, -1, -1) == -one_compound);
ok = ok && (-half4(1) == -one_splat);
ok = ok && (-half4(1, 1, 1, 1) == -one_splat);
ok = ok && (-half4(1) == -one_compound);
ok = ok && (-half4(1, 1, 1, 1) == -one_compound);
ok = ok && (half4(-1) == -one_compound);
ok = ok && (half4(-1) == -half4(-half2(-1), half2(1)));
ok = ok && (half4(1) != -half4(1));
ok = ok && (-half4(two) == half4(-two, half3(-two)));
ok = ok && (-half2(-one, one + one) == -half2(one - two, two));
return ok;
}
bool test_ivec() {
int one = 1;
const int two = 2;
const int4 one_splat = int4(1);
const int4 one_compound = int4(1, 1, 1, 1);
bool ok = true;
ok = ok && (int4(-1) == -one_splat);
ok = ok && (int4(-1, -1, -1, -1) == -one_splat);
ok = ok && (int4(-1) == -one_compound);
ok = ok && (int4(-1, -1, -1, -1) == -one_compound);
ok = ok && (-int4(1) == -one_splat);
ok = ok && (-int4(1, 1, 1, 1) == -one_splat);
ok = ok && (-int4(1) == -one_compound);
ok = ok && (-int4(1, 1, 1, 1) == -one_compound);
ok = ok && (int4(-1) == -int4(-int2(-1), int2(1)));
ok = ok && (int4(1) != -int4(1));
ok = ok && (-int4(two) == int4(-two, int3(-two)));
ok = ok && (-int2(-one, one + one) == -int2(one - two, two));
return ok;
}
bool test_mat() {
const float3x3 one_diagonal = float3x3(1);
const float3x3 one_compound = float3x3(1, 0, 0,
0, 1, 0,
0, 0, 1);
bool ok = true;
ok = ok && (float3x3(-1) == -one_diagonal);
ok = ok && (float3x3(-1, 0, 0, 0, -1, 0, 0, 0, -1) == -one_diagonal);
ok = ok && (float3x3(-1) == -one_compound);
ok = ok && (float3x3(-1, 0, 0, 0, -1, 0, 0, 0, -1) == -one_compound);
ok = ok && (-float3x3(1) == -one_diagonal);
ok = ok && (-float3x3(1, 0, 0, 0, 1, 0, 0, 0, 1) == -one_diagonal);
ok = ok && (-float3x3(1) == -one_compound);
ok = ok && (-float3x3(1, 0, 0, 0, 1, 0, 0, 0, 1) == -one_compound);
return ok;
}
half4 main(float2 coords) {
return test_fvec() && test_ivec() && test_mat() ? colorGreen : colorRed;
}

View File

@ -19,30 +19,30 @@
namespace SkSL {
static ExpressionArray negate_operands(const Context& context, ExpressionArray operands);
static ExpressionArray negate_operands(const Context& context, const ExpressionArray& operands);
static std::unique_ptr<Expression> negate_operand(const Context& context,
std::unique_ptr<Expression> operand) {
const Expression* value = ConstantFolder::GetConstantValueForVariable(*operand);
static std::unique_ptr<Expression> simplify_negation(const Context& context,
const Expression& originalExpr) {
const Expression* value = ConstantFolder::GetConstantValueForVariable(originalExpr);
switch (value->kind()) {
case Expression::Kind::kFloatLiteral:
// Convert -floatLiteral(1) to floatLiteral(-1).
return FloatLiteral::Make(operand->fOffset,
return FloatLiteral::Make(originalExpr.fOffset,
-value->as<FloatLiteral>().value(),
&value->type());
case Expression::Kind::kIntLiteral:
// Convert -intLiteral(1) to intLiteral(-1).
return IntLiteral::Make(operand->fOffset,
return IntLiteral::Make(originalExpr.fOffset,
-value->as<IntLiteral>().value(),
&value->type());
case Expression::Kind::kPrefix:
if (context.fConfig->fSettings.fOptimize) {
// Convert `-(-expression)` into `expression`.
PrefixExpression& prefix = operand->as<PrefixExpression>();
const PrefixExpression& prefix = value->as<PrefixExpression>();
if (prefix.getOperator().kind() == Token::Kind::TK_MINUS) {
return std::move(prefix.operand());
return prefix.operand()->clone();
}
}
break;
@ -50,55 +50,69 @@ static std::unique_ptr<Expression> negate_operand(const Context& context,
case Expression::Kind::kConstructorArray:
// Convert `-array[N](literal, ...)` into `array[N](-literal, ...)`.
if (context.fConfig->fSettings.fOptimize && value->isCompileTimeConstant()) {
ConstructorArray& ctor = operand->as<ConstructorArray>();
return ConstructorArray::Make(
context, ctor.fOffset, ctor.type(),
negate_operands(context, std::move(ctor.arguments())));
const ConstructorArray& ctor = value->as<ConstructorArray>();
return ConstructorArray::Make(context, originalExpr.fOffset, ctor.type(),
negate_operands(context, ctor.arguments()));
}
break;
case Expression::Kind::kConstructorDiagonalMatrix:
// Convert `-matrix(literal)` into `matrix(-literal)`.
if (context.fConfig->fSettings.fOptimize && value->isCompileTimeConstant()) {
ConstructorDiagonalMatrix& ctor = operand->as<ConstructorDiagonalMatrix>();
return ConstructorDiagonalMatrix::Make(
context, ctor.fOffset, ctor.type(),
negate_operand(context, std::move(ctor.argument())));
const ConstructorDiagonalMatrix& ctor = value->as<ConstructorDiagonalMatrix>();
return ConstructorDiagonalMatrix::Make(context, originalExpr.fOffset, ctor.type(),
simplify_negation(context, *ctor.argument()));
}
break;
case Expression::Kind::kConstructorSplat:
// Convert `-vector(literal)` into `vector(-literal)`.
if (context.fConfig->fSettings.fOptimize && value->isCompileTimeConstant()) {
ConstructorSplat& ctor = operand->as<ConstructorSplat>();
return ConstructorSplat::Make(context, ctor.fOffset, ctor.type(),
negate_operand(context, std::move(ctor.argument())));
const ConstructorSplat& ctor = value->as<ConstructorSplat>();
return ConstructorSplat::Make(context, originalExpr.fOffset, ctor.type(),
simplify_negation(context, *ctor.argument()));
}
break;
case Expression::Kind::kConstructorCompound:
// Convert `-vecN(literal, ...)` into `vecN(-literal, ...)`.
if (context.fConfig->fSettings.fOptimize && value->isCompileTimeConstant()) {
ConstructorCompound& ctor = operand->as<ConstructorCompound>();
return ConstructorCompound::Make(
context, ctor.fOffset, ctor.type(),
negate_operands(context, std::move(ctor.arguments())));
const ConstructorCompound& ctor = value->as<ConstructorCompound>();
return ConstructorCompound::Make(context, originalExpr.fOffset, ctor.type(),
negate_operands(context, ctor.arguments()));
}
break;
default:
break;
}
// No simplified form; convert expression to Prefix(TK_MINUS, expression).
return std::make_unique<PrefixExpression>(Token::Kind::TK_MINUS, std::move(operand));
return nullptr;
}
static ExpressionArray negate_operands(const Context& context, ExpressionArray operands) {
for (std::unique_ptr<Expression>& arg : operands) {
arg = negate_operand(context, std::move(arg));
static ExpressionArray negate_operands(const Context& context, const ExpressionArray& array) {
ExpressionArray replacement;
replacement.reserve_back(array.size());
for (const std::unique_ptr<Expression>& expr : array) {
// The logic below is very similar to `negate_operand`, but with different ownership rules.
if (std::unique_ptr<Expression> simplified = simplify_negation(context, *expr)) {
replacement.push_back(std::move(simplified));
} else {
replacement.push_back(std::make_unique<PrefixExpression>(Token::Kind::TK_MINUS,
expr->clone()));
}
}
return operands;
return replacement;
}
static std::unique_ptr<Expression> negate_operand(const Context& context,
std::unique_ptr<Expression> value) {
// Attempt to simplify this negation (e.g. eliminate double negation, literal values)
if (std::unique_ptr<Expression> simplified = simplify_negation(context, *value)) {
return simplified;
}
// No simplified form; convert expression to Prefix(TK_MINUS, expression).
return std::make_unique<PrefixExpression>(Token::Kind::TK_MINUS, std::move(value));
}
static std::unique_ptr<Expression> logical_not_operand(const Context& context,

View File

@ -267,7 +267,7 @@ SKSL_TEST(SkSLMatrixEquality, "shared/MatrixEquality.sksl")
SKSL_TEST(SkSLMatrixScalarSplat, "shared/MatrixScalarSplat.sksl")
SKSL_TEST(SkSLMatrixToVectorCast, "shared/MatrixToVectorCast.sksl")
SKSL_TEST(SkSLMultipleAssignments, "shared/MultipleAssignments.sksl")
SKSL_TEST(SkSLNegatedVectorLiteral, "shared/NegatedVectorLiteral.sksl")
SKSL_TEST(SkSLNegation, "shared/Negation.sksl")
SKSL_TEST(SkSLNumberCasts, "shared/NumberCasts.sksl")
SKSL_TEST(SkSLOperatorsES2, "shared/OperatorsES2.sksl")
SKSL_TEST_ES3(SkSLOperatorsES3, "shared/OperatorsES3.sksl")

View File

@ -1,211 +0,0 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
OpExecutionMode %_entrypoint_v OriginUpperLeft
OpName %sk_FragColor "sk_FragColor"
OpName %sk_Clockwise "sk_Clockwise"
OpName %_UniformBuffer "_UniformBuffer"
OpMemberName %_UniformBuffer 0 "colorGreen"
OpMemberName %_UniformBuffer 1 "colorRed"
OpName %_entrypoint_v "_entrypoint_v"
OpName %test_int_b "test_int_b"
OpName %one "one"
OpName %two "two"
OpName %result "result"
OpName %main "main"
OpName %_0_one "_0_one"
OpName %_1_two "_1_two"
OpName %_2_result "_2_result"
OpDecorate %sk_FragColor RelaxedPrecision
OpDecorate %sk_FragColor Location 0
OpDecorate %sk_FragColor Index 0
OpDecorate %sk_Clockwise BuiltIn FrontFacing
OpMemberDecorate %_UniformBuffer 0 Offset 0
OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
OpMemberDecorate %_UniformBuffer 1 Offset 16
OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
OpDecorate %_UniformBuffer Block
OpDecorate %11 Binding 0
OpDecorate %11 DescriptorSet 0
OpDecorate %82 RelaxedPrecision
OpDecorate %84 RelaxedPrecision
OpDecorate %89 RelaxedPrecision
OpDecorate %91 RelaxedPrecision
OpDecorate %92 RelaxedPrecision
OpDecorate %93 RelaxedPrecision
OpDecorate %94 RelaxedPrecision
OpDecorate %102 RelaxedPrecision
OpDecorate %103 RelaxedPrecision
OpDecorate %108 RelaxedPrecision
OpDecorate %137 RelaxedPrecision
OpDecorate %139 RelaxedPrecision
OpDecorate %140 RelaxedPrecision
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%sk_FragColor = OpVariable %_ptr_Output_v4float Output
%bool = OpTypeBool
%_ptr_Input_bool = OpTypePointer Input %bool
%sk_Clockwise = OpVariable %_ptr_Input_bool Input
%_UniformBuffer = OpTypeStruct %v4float %v4float
%_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
%11 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
%void = OpTypeVoid
%16 = OpTypeFunction %void
%v2float = OpTypeVector %float 2
%float_0 = OpConstant %float 0
%20 = OpConstantComposite %v2float %float_0 %float_0
%_ptr_Function_v2float = OpTypePointer Function %v2float
%24 = OpTypeFunction %bool
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%v4int = OpTypeVector %int 4
%_ptr_Function_v4int = OpTypePointer Function %v4int
%int_0 = OpConstant %int 0
%v2int = OpTypeVector %int 2
%v2bool = OpTypeVector %bool 2
%int_3 = OpConstant %int 3
%70 = OpTypeFunction %v4float %_ptr_Function_v2float
%_ptr_Function_float = OpTypePointer Function %float
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%_ptr_Function_v4float = OpTypePointer Function %v4float
%v3float = OpTypeVector %float 3
%v4bool = OpTypeVector %bool 4
%float_n2 = OpConstant %float -2
%102 = OpConstantComposite %v2float %float_1 %float_n2
%false = OpConstantFalse %bool
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%_entrypoint_v = OpFunction %void None %16
%17 = OpLabel
%21 = OpVariable %_ptr_Function_v2float Function
OpStore %21 %20
%23 = OpFunctionCall %v4float %main %21
OpStore %sk_FragColor %23
OpReturn
OpFunctionEnd
%test_int_b = OpFunction %bool None %24
%25 = OpLabel
%one = OpVariable %_ptr_Function_int Function
%two = OpVariable %_ptr_Function_int Function
%result = OpVariable %_ptr_Function_v4int Function
OpStore %one %int_1
OpStore %two %int_2
%35 = OpAccessChain %_ptr_Function_int %result %int_0
OpStore %35 %int_1
%37 = OpAccessChain %_ptr_Function_int %result %int_1
OpStore %37 %int_1
%38 = OpAccessChain %_ptr_Function_int %result %int_2
OpStore %38 %int_1
%42 = OpLoad %int %one
%41 = OpSNegate %int %42
%43 = OpLoad %int %one
%44 = OpLoad %int %one
%45 = OpIAdd %int %43 %44
%46 = OpCompositeConstruct %v2int %41 %45
%39 = OpSNegate %v2int %46
%48 = OpLoad %int %one
%49 = OpLoad %int %two
%50 = OpISub %int %48 %49
%51 = OpCompositeConstruct %v2int %50 %int_2
%47 = OpSNegate %v2int %51
%52 = OpIEqual %v2bool %39 %47
%54 = OpAll %bool %52
%55 = OpSelect %int %54 %int_1 %int_0
%56 = OpAccessChain %_ptr_Function_int %result %int_3
OpStore %56 %55
%58 = OpLoad %v4int %result
%59 = OpCompositeExtract %int %58 0
%60 = OpLoad %v4int %result
%61 = OpCompositeExtract %int %60 1
%62 = OpIMul %int %59 %61
%63 = OpLoad %v4int %result
%64 = OpCompositeExtract %int %63 2
%65 = OpIMul %int %62 %64
%66 = OpLoad %v4int %result
%67 = OpCompositeExtract %int %66 3
%68 = OpIMul %int %65 %67
%69 = OpINotEqual %bool %68 %int_0
OpReturnValue %69
OpFunctionEnd
%main = OpFunction %v4float None %70
%71 = OpFunctionParameter %_ptr_Function_v2float
%72 = OpLabel
%_0_one = OpVariable %_ptr_Function_float Function
%_1_two = OpVariable %_ptr_Function_float Function
%_2_result = OpVariable %_ptr_Function_v4float Function
%131 = OpVariable %_ptr_Function_v4float Function
OpStore %_0_one %float_1
OpStore %_1_two %float_2
%80 = OpAccessChain %_ptr_Function_float %_2_result %int_0
OpStore %80 %float_1
%81 = OpAccessChain %_ptr_Function_float %_2_result %int_1
OpStore %81 %float_1
%83 = OpLoad %float %_1_two
%84 = OpCompositeConstruct %v4float %83 %83 %83 %83
%82 = OpFNegate %v4float %84
%86 = OpLoad %float %_1_two
%85 = OpFNegate %float %86
%88 = OpLoad %float %_1_two
%87 = OpFNegate %float %88
%89 = OpCompositeConstruct %v3float %87 %87 %87
%91 = OpCompositeExtract %float %89 0
%92 = OpCompositeExtract %float %89 1
%93 = OpCompositeExtract %float %89 2
%94 = OpCompositeConstruct %v4float %85 %91 %92 %93
%95 = OpFOrdEqual %v4bool %82 %94
%97 = OpAll %bool %95
%98 = OpSelect %int %97 %int_1 %int_0
%99 = OpConvertSToF %float %98
%100 = OpAccessChain %_ptr_Function_float %_2_result %int_2
OpStore %100 %99
%104 = OpLoad %float %_0_one
%105 = OpLoad %float %_1_two
%106 = OpFSub %float %104 %105
%107 = OpLoad %float %_1_two
%108 = OpCompositeConstruct %v2float %106 %107
%103 = OpFNegate %v2float %108
%109 = OpFOrdEqual %v2bool %102 %103
%110 = OpAll %bool %109
%111 = OpSelect %int %110 %int_1 %int_0
%112 = OpConvertSToF %float %111
%113 = OpAccessChain %_ptr_Function_float %_2_result %int_3
OpStore %113 %112
%115 = OpLoad %v4float %_2_result
%116 = OpCompositeExtract %float %115 0
%117 = OpLoad %v4float %_2_result
%118 = OpCompositeExtract %float %117 1
%119 = OpFMul %float %116 %118
%120 = OpLoad %v4float %_2_result
%121 = OpCompositeExtract %float %120 2
%122 = OpFMul %float %119 %121
%123 = OpLoad %v4float %_2_result
%124 = OpCompositeExtract %float %123 3
%125 = OpFMul %float %122 %124
%126 = OpFUnordNotEqual %bool %125 %float_0
OpSelectionMerge %128 None
OpBranchConditional %126 %127 %128
%127 = OpLabel
%129 = OpFunctionCall %bool %test_int_b
OpBranch %128
%128 = OpLabel
%130 = OpPhi %bool %false %72 %129 %127
OpSelectionMerge %134 None
OpBranchConditional %130 %132 %133
%132 = OpLabel
%135 = OpAccessChain %_ptr_Uniform_v4float %11 %int_0
%137 = OpLoad %v4float %135
OpStore %131 %137
OpBranch %134
%133 = OpLabel
%138 = OpAccessChain %_ptr_Uniform_v4float %11 %int_1
%139 = OpLoad %v4float %138
OpStore %131 %139
OpBranch %134
%134 = OpLabel
%140 = OpLoad %v4float %131
OpReturnValue %140
OpFunctionEnd

View File

@ -1,24 +0,0 @@
out vec4 sk_FragColor;
uniform vec4 colorGreen;
uniform vec4 colorRed;
bool test_int_b() {
int one = 1;
const int two = 2;
ivec4 result;
result.x = 1;
result.y = 1;
result.z = 1;
result.w = int(-ivec2(-one, one + one) == -ivec2(one - two, 2) ? 1 : 0);
return bool(((result.x * result.y) * result.z) * result.w);
}
vec4 main() {
const float _0_one = 1.0;
float _1_two = 2.0;
vec4 _2_result;
_2_result.x = 1.0;
_2_result.y = 1.0;
_2_result.z = float(-vec4(_1_two) == vec4(-_1_two, vec3(-_1_two)) ? 1 : 0);
_2_result.w = float(vec2(1.0, -2.0) == -vec2(_0_one - _1_two, _1_two) ? 1 : 0);
return bool(((_2_result.x * _2_result.y) * _2_result.z) * _2_result.w) && test_int_b() ? colorGreen : colorRed;
}

View File

@ -1,35 +0,0 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct Uniforms {
float4 colorGreen;
float4 colorRed;
};
struct Inputs {
};
struct Outputs {
float4 sk_FragColor [[color(0)]];
};
bool test_int_b() {
int one = 1;
const int two = 2;
int4 result;
result.x = 1;
result.y = 1;
result.z = 1;
result.w = int(all(-int2(-one, one + one) == -int2(one - two, 2)) ? 1 : 0);
return bool(((result.x * result.y) * result.z) * result.w);
}
fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
Outputs _out;
(void)_out;
const float _0_one = 1.0;
float _1_two = 2.0;
float4 _2_result;
_2_result.x = 1.0;
_2_result.y = 1.0;
_2_result.z = float(all(-float4(_1_two) == float4(-_1_two, float3(-_1_two))) ? 1 : 0);
_2_result.w = float(all(float2(1.0, -2.0) == -float2(_0_one - _1_two, _1_two)) ? 1 : 0);
_out.sk_FragColor = bool(((_2_result.x * _2_result.y) * _2_result.z) * _2_result.w) && test_int_b() ? _uniforms.colorGreen : _uniforms.colorRed;
return _out;
}

View File

@ -0,0 +1,215 @@
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
OpExecutionMode %_entrypoint_v OriginUpperLeft
OpName %sk_FragColor "sk_FragColor"
OpName %sk_Clockwise "sk_Clockwise"
OpName %_UniformBuffer "_UniformBuffer"
OpMemberName %_UniformBuffer 0 "colorGreen"
OpMemberName %_UniformBuffer 1 "colorRed"
OpName %_entrypoint_v "_entrypoint_v"
OpName %test_ivec_b "test_ivec_b"
OpName %one "one"
OpName %two "two"
OpName %ok "ok"
OpName %test_mat_b "test_mat_b"
OpName %ok_0 "ok"
OpName %main "main"
OpName %_0_one "_0_one"
OpName %_1_two "_1_two"
OpName %_4_ok "_4_ok"
OpDecorate %sk_FragColor RelaxedPrecision
OpDecorate %sk_FragColor Location 0
OpDecorate %sk_FragColor Index 0
OpDecorate %sk_Clockwise BuiltIn FrontFacing
OpMemberDecorate %_UniformBuffer 0 Offset 0
OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
OpMemberDecorate %_UniformBuffer 1 Offset 16
OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
OpDecorate %_UniformBuffer Block
OpDecorate %12 Binding 0
OpDecorate %12 DescriptorSet 0
OpDecorate %37 RelaxedPrecision
OpDecorate %57 RelaxedPrecision
OpDecorate %60 RelaxedPrecision
OpDecorate %70 RelaxedPrecision
OpDecorate %73 RelaxedPrecision
OpDecorate %75 RelaxedPrecision
OpDecorate %80 RelaxedPrecision
OpDecorate %82 RelaxedPrecision
OpDecorate %83 RelaxedPrecision
OpDecorate %84 RelaxedPrecision
OpDecorate %85 RelaxedPrecision
OpDecorate %90 RelaxedPrecision
OpDecorate %94 RelaxedPrecision
OpDecorate %95 RelaxedPrecision
OpDecorate %100 RelaxedPrecision
OpDecorate %104 RelaxedPrecision
OpDecorate %121 RelaxedPrecision
OpDecorate %123 RelaxedPrecision
OpDecorate %124 RelaxedPrecision
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%sk_FragColor = OpVariable %_ptr_Output_v4float Output
%bool = OpTypeBool
%_ptr_Input_bool = OpTypePointer Input %bool
%sk_Clockwise = OpVariable %_ptr_Input_bool Input
%_UniformBuffer = OpTypeStruct %v4float %v4float
%_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
%12 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
%void = OpTypeVoid
%17 = OpTypeFunction %void
%v2float = OpTypeVector %float 2
%float_0 = OpConstant %float 0
%21 = OpConstantComposite %v2float %float_0 %float_0
%_ptr_Function_v2float = OpTypePointer Function %v2float
%25 = OpTypeFunction %bool
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%_ptr_Function_bool = OpTypePointer Function %bool
%true = OpConstantTrue %bool
%false = OpConstantFalse %bool
%v2int = OpTypeVector %int 2
%v2bool = OpTypeVector %bool 2
%61 = OpTypeFunction %v4float %_ptr_Function_v2float
%_ptr_Function_float = OpTypePointer Function %float
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%v3float = OpTypeVector %float 3
%v4bool = OpTypeVector %bool 4
%float_n2 = OpConstant %float -2
%94 = OpConstantComposite %v2float %float_1 %float_n2
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%int_0 = OpConstant %int 0
%_entrypoint_v = OpFunction %void None %17
%18 = OpLabel
%22 = OpVariable %_ptr_Function_v2float Function
OpStore %22 %21
%24 = OpFunctionCall %v4float %main %22
OpStore %sk_FragColor %24
OpReturn
OpFunctionEnd
%test_ivec_b = OpFunction %bool None %25
%26 = OpLabel
%one = OpVariable %_ptr_Function_int Function
%two = OpVariable %_ptr_Function_int Function
%ok = OpVariable %_ptr_Function_bool Function
OpStore %one %int_1
OpStore %two %int_2
OpStore %ok %true
%37 = OpLoad %bool %ok
OpSelectionMerge %39 None
OpBranchConditional %37 %38 %39
%38 = OpLabel
%43 = OpLoad %int %one
%42 = OpSNegate %int %43
%44 = OpLoad %int %one
%45 = OpLoad %int %one
%46 = OpIAdd %int %44 %45
%47 = OpCompositeConstruct %v2int %42 %46
%40 = OpSNegate %v2int %47
%49 = OpLoad %int %one
%50 = OpLoad %int %two
%51 = OpISub %int %49 %50
%52 = OpCompositeConstruct %v2int %51 %int_2
%48 = OpSNegate %v2int %52
%53 = OpIEqual %v2bool %40 %48
%55 = OpAll %bool %53
OpBranch %39
%39 = OpLabel
%56 = OpPhi %bool %false %26 %55 %38
OpStore %ok %56
%57 = OpLoad %bool %ok
OpReturnValue %57
OpFunctionEnd
%test_mat_b = OpFunction %bool None %25
%58 = OpLabel
%ok_0 = OpVariable %_ptr_Function_bool Function
OpStore %ok_0 %true
%60 = OpLoad %bool %ok_0
OpReturnValue %60
OpFunctionEnd
%main = OpFunction %v4float None %61
%62 = OpFunctionParameter %_ptr_Function_v2float
%63 = OpLabel
%_0_one = OpVariable %_ptr_Function_float Function
%_1_two = OpVariable %_ptr_Function_float Function
%_4_ok = OpVariable %_ptr_Function_bool Function
%113 = OpVariable %_ptr_Function_v4float Function
OpStore %_0_one %float_1
OpStore %_1_two %float_2
OpStore %_4_ok %true
%70 = OpLoad %bool %_4_ok
OpSelectionMerge %72 None
OpBranchConditional %70 %71 %72
%71 = OpLabel
%74 = OpLoad %float %_1_two
%75 = OpCompositeConstruct %v4float %74 %74 %74 %74
%73 = OpFNegate %v4float %75
%77 = OpLoad %float %_1_two
%76 = OpFNegate %float %77
%79 = OpLoad %float %_1_two
%78 = OpFNegate %float %79
%80 = OpCompositeConstruct %v3float %78 %78 %78
%82 = OpCompositeExtract %float %80 0
%83 = OpCompositeExtract %float %80 1
%84 = OpCompositeExtract %float %80 2
%85 = OpCompositeConstruct %v4float %76 %82 %83 %84
%86 = OpFOrdEqual %v4bool %73 %85
%88 = OpAll %bool %86
OpBranch %72
%72 = OpLabel
%89 = OpPhi %bool %false %63 %88 %71
OpStore %_4_ok %89
%90 = OpLoad %bool %_4_ok
OpSelectionMerge %92 None
OpBranchConditional %90 %91 %92
%91 = OpLabel
%96 = OpLoad %float %_0_one
%97 = OpLoad %float %_1_two
%98 = OpFSub %float %96 %97
%99 = OpLoad %float %_1_two
%100 = OpCompositeConstruct %v2float %98 %99
%95 = OpFNegate %v2float %100
%101 = OpFOrdEqual %v2bool %94 %95
%102 = OpAll %bool %101
OpBranch %92
%92 = OpLabel
%103 = OpPhi %bool %false %72 %102 %91
OpStore %_4_ok %103
%104 = OpLoad %bool %_4_ok
OpSelectionMerge %106 None
OpBranchConditional %104 %105 %106
%105 = OpLabel
%107 = OpFunctionCall %bool %test_ivec_b
OpBranch %106
%106 = OpLabel
%108 = OpPhi %bool %false %92 %107 %105
OpSelectionMerge %110 None
OpBranchConditional %108 %109 %110
%109 = OpLabel
%111 = OpFunctionCall %bool %test_mat_b
OpBranch %110
%110 = OpLabel
%112 = OpPhi %bool %false %106 %111 %109
OpSelectionMerge %117 None
OpBranchConditional %112 %115 %116
%115 = OpLabel
%118 = OpAccessChain %_ptr_Uniform_v4float %12 %int_0
%121 = OpLoad %v4float %118
OpStore %113 %121
OpBranch %117
%116 = OpLabel
%122 = OpAccessChain %_ptr_Uniform_v4float %12 %int_1
%123 = OpLoad %v4float %122
OpStore %113 %123
OpBranch %117
%117 = OpLabel
%124 = OpLoad %v4float %113
OpReturnValue %124
OpFunctionEnd

View File

@ -0,0 +1,23 @@
out vec4 sk_FragColor;
uniform vec4 colorGreen;
uniform vec4 colorRed;
bool test_ivec_b() {
int one = 1;
const int two = 2;
bool ok = true;
ok = ok && -ivec2(-one, one + one) == -ivec2(one - two, 2);
return ok;
}
bool test_mat_b() {
bool ok = true;
return ok;
}
vec4 main() {
const float _0_one = 1.0;
float _1_two = 2.0;
bool _4_ok = true;
_4_ok = _4_ok && -vec4(_1_two) == vec4(-_1_two, vec3(-_1_two));
_4_ok = _4_ok && vec2(1.0, -2.0) == -vec2(_0_one - _1_two, _1_two);
return (_4_ok && test_ivec_b()) && test_mat_b() ? colorGreen : colorRed;
}

View File

@ -0,0 +1,34 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct Uniforms {
float4 colorGreen;
float4 colorRed;
};
struct Inputs {
};
struct Outputs {
float4 sk_FragColor [[color(0)]];
};
bool test_ivec_b() {
int one = 1;
const int two = 2;
bool ok = true;
ok = ok && all(-int2(-one, one + one) == -int2(one - two, 2));
return ok;
}
bool test_mat_b() {
bool ok = true;
return ok;
}
fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
Outputs _out;
(void)_out;
const float _0_one = 1.0;
float _1_two = 2.0;
bool _4_ok = true;
_4_ok = _4_ok && all(-float4(_1_two) == float4(-_1_two, float3(-_1_two)));
_4_ok = _4_ok && all(float2(1.0, -2.0) == -float2(_0_one - _1_two, _1_two));
_out.sk_FragColor = (_4_ok && test_ivec_b()) && test_mat_b() ? _uniforms.colorGreen : _uniforms.colorRed;
return _out;
}