Improve constant folding for int vectors.

This implements constant folding optimizations on int vectors
(== != + - * /) that were previously only supported on float vectors.

Bug: skia:10908
Change-Id: Ibf61ab43eb7ae2ce8e99cce21cc55777359817e5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/332424
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2020-11-06 11:37:05 -05:00 committed by Skia Commit-Bot
parent 56277e5a6e
commit cf27b4f744
6 changed files with 98 additions and 77 deletions

View File

@ -1721,6 +1721,57 @@ static std::unique_ptr<Expression> short_circuit_boolean(const Context& context,
}
}
template <typename T>
std::unique_ptr<Expression> IRGenerator::constantFoldVector(const Expression& left,
Token::Kind op,
const Expression& right) const {
SkASSERT(left.type() == right.type());
const Type& type = left.type();
// Handle boolean operations: == !=
if (op == Token::Kind::TK_EQEQ || op == Token::Kind::TK_NEQ) {
if (left.kind() == right.kind()) {
bool result = left.compareConstant(fContext, right) ^ (op == Token::Kind::TK_NEQ);
return std::make_unique<BoolLiteral>(fContext, left.fOffset, result);
}
return nullptr;
}
// Handle floating-point arithmetic: + - * /
const auto vectorComponentwiseFold = [&](auto foldFn) -> std::unique_ptr<Constructor> {
ExpressionArray args;
for (int i = 0; i < type.columns(); i++) {
T value = foldFn(left.getVecComponent<T>(i), right.getVecComponent<T>(i));
args.push_back(std::make_unique<Literal<T>>(fContext, left.fOffset, value));
}
return std::make_unique<Constructor>(left.fOffset, &type, std::move(args));
};
const auto isVectorDivisionByZero = [&]() -> bool {
for (int i = 0; i < type.columns(); i++) {
if (right.getVecComponent<T>(i) == 0) {
return true;
}
}
return false;
};
switch (op) {
case Token::Kind::TK_PLUS: return vectorComponentwiseFold([](T a, T b) { return a + b; });
case Token::Kind::TK_MINUS: return vectorComponentwiseFold([](T a, T b) { return a - b; });
case Token::Kind::TK_STAR: return vectorComponentwiseFold([](T a, T b) { return a * b; });
case Token::Kind::TK_SLASH: {
if (isVectorDivisionByZero()) {
fErrors.error(right.fOffset, "division by zero");
return nullptr;
}
return vectorComponentwiseFold([](T a, T b) { return a / b; });
}
default:
return nullptr;
}
}
std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left,
Token::Kind op,
const Expression& right) const {
@ -1836,46 +1887,12 @@ std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left,
}
const Type& leftType = left.type();
const Type& rightType = right.type();
if (leftType.typeKind() == Type::TypeKind::kVector && leftType.componentType().isFloat() &&
leftType == rightType) {
ExpressionArray args;
#define RETURN_VEC_COMPONENTWISE_RESULT(op) \
for (int i = 0; i < leftType.columns(); i++) { \
SKSL_FLOAT value = left.getFVecComponent(i) op right.getFVecComponent(i); \
args.push_back(std::make_unique<FloatLiteral>(fContext, left.fOffset, value)); \
} \
return std::make_unique<Constructor>(left.fOffset, &leftType, std::move(args))
switch (op) {
case Token::Kind::TK_EQEQ:
if (left.kind() == right.kind()) {
return std::make_unique<BoolLiteral>(fContext, left.fOffset,
left.compareConstant(fContext, right));
}
return nullptr;
case Token::Kind::TK_NEQ:
if (left.kind() == right.kind()) {
return std::make_unique<BoolLiteral>(fContext, left.fOffset,
!left.compareConstant(fContext, right));
}
return nullptr;
case Token::Kind::TK_PLUS: RETURN_VEC_COMPONENTWISE_RESULT(+);
case Token::Kind::TK_MINUS: RETURN_VEC_COMPONENTWISE_RESULT(-);
case Token::Kind::TK_STAR: RETURN_VEC_COMPONENTWISE_RESULT(*);
case Token::Kind::TK_SLASH:
for (int i = 0; i < leftType.columns(); i++) {
SKSL_FLOAT rvalue = right.getFVecComponent(i);
if (rvalue == 0.0) {
fErrors.error(right.fOffset, "division by zero");
return nullptr;
}
SKSL_FLOAT value = left.getFVecComponent(i) / rvalue;
args.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1, value));
}
return std::make_unique<Constructor>(/*offset=*/-1, &leftType, std::move(args));
default:
return nullptr;
if (leftType.typeKind() == Type::TypeKind::kVector && leftType == rightType) {
if (leftType.componentType().isFloat()) {
return constantFoldVector<SKSL_FLOAT>(left, op, right);
} else if (leftType.componentType().isInteger()) {
return constantFoldVector<SKSL_INT>(left, op, right);
}
#undef RETURN_VEC_COMPONENTWISE_RESULT
}
if (leftType.typeKind() == Type::TypeKind::kMatrix &&
rightType.typeKind() == Type::TypeKind::kMatrix &&

View File

@ -171,6 +171,10 @@ private:
ExpressionArray arguments);
CoercionCost coercionCost(const Expression& expr, const Type& type);
std::unique_ptr<Expression> coerce(std::unique_ptr<Expression> expr, const Type& type);
template <typename T>
std::unique_ptr<Expression> constantFoldVector(const Expression& left,
Token::Kind op,
const Expression& right) const;
std::unique_ptr<Block> convertBlock(const ASTNode& block);
std::unique_ptr<Statement> convertBreak(const ASTNode& b);
std::unique_ptr<Expression> convertNumberConstructor(int offset,

View File

@ -9,10 +9,10 @@ void main() {
}
{
sk_FragColor.x = float(ivec4(-1) == ivec4(ivec2(-1), ivec2(-1)) ? 1 : 0);
sk_FragColor.y = float(ivec4(1) != ivec4(-1) ? 1 : 0);
sk_FragColor.z = float(ivec4(-2) == ivec4(-2, ivec3(-2)) ? 1 : 0);
sk_FragColor.w = float(ivec2(1, -2) == ivec2(1, -2) ? 1 : 0);
sk_FragColor.x = 1.0;
sk_FragColor.y = 1.0;
sk_FragColor.z = 1.0;
sk_FragColor.w = 1.0;
}
}

View File

@ -17,10 +17,10 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front
}
{
_out->sk_FragColor.x = float(all(int4(-1) == int4(int2(-1), int2(-1))) ? 1 : 0);
_out->sk_FragColor.y = float(any(int4(1) != int4(-1)) ? 1 : 0);
_out->sk_FragColor.z = float(all(int4(-2) == int4(-2, int3(-2))) ? 1 : 0);
_out->sk_FragColor.w = float(all(int2(1, -2) == int2(1, -2)) ? 1 : 0);
_out->sk_FragColor.x = 1.0;
_out->sk_FragColor.y = 1.0;
_out->sk_FragColor.z = 1.0;
_out->sk_FragColor.w = 1.0;
}
return *_out;

View File

@ -52,21 +52,21 @@ void main() {
{
ivec4 _0_result;
_0_result.x = 2;
_0_result = ivec4(ivec2(1), ivec2(2, 3)) + ivec4(5, 6, 7, 8);
_0_result = ivec4(8, ivec3(10)) - ivec4(1);
_0_result = ivec4(2) * ivec4(1, 2, 3, 4);
_0_result = ivec4(12) / ivec4(1, 2, 3, 4);
sk_FragColor.x = float((ivec4(12) / ivec4(1, 2, 3, 4)).y);
sk_FragColor.x = ivec4(1) == ivec4(1) ? 1.0 : -1.0;
sk_FragColor.x = ivec4(1) == ivec4(2) ? 2.0 : -2.0;
sk_FragColor.x = ivec2(1) == ivec2(1, 1) ? 3.0 : -3.0;
sk_FragColor.x = ivec2(1, 1) == ivec2(1, 1) ? 4.0 : -4.0;
sk_FragColor.x = ivec2(1) == ivec2(1, 0) ? 5.0 : -5.0;
sk_FragColor.x = ivec4(1) == ivec4(ivec2(1), ivec2(1)) ? 6.0 : -6.0;
sk_FragColor.x = ivec4(ivec3(1), 1) == ivec4(ivec2(1), ivec2(1)) ? 7.0 : -7.0;
sk_FragColor.x = ivec4(ivec3(1), 1) == ivec4(ivec2(1), 1, 0) ? 8.0 : -8.0;
sk_FragColor.x = ivec2(1) != ivec2(1, 0) ? 9.0 : -9.0;
sk_FragColor.x = ivec4(1) != ivec4(ivec2(1), ivec2(1)) ? 10.0 : -10.0;
_0_result = ivec4(6, 7, 9, 11);
_0_result = ivec4(7, 9, 9, 9);
_0_result = ivec4(2, 4, 6, 8);
_0_result = ivec4(12, 6, 4, 3);
sk_FragColor.x = 6.0;
sk_FragColor.x = 1.0;
sk_FragColor.x = -2.0;
sk_FragColor.x = 3.0;
sk_FragColor.x = 4.0;
sk_FragColor.x = -5.0;
sk_FragColor.x = 6.0;
sk_FragColor.x = 7.0;
sk_FragColor.x = -8.0;
sk_FragColor.x = 9.0;
sk_FragColor.x = -10.0;
_0_result = ivec4(int(sqrt(1.0)));
_0_result = ivec4(int(sqrt(2.0)));
_0_result = ivec4(0);

View File

@ -60,21 +60,21 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front
{
int4 _0_result;
_0_result.x = 2;
_0_result = int4(int2(1), int2(2, 3)) + int4(5, 6, 7, 8);
_0_result = int4(8, int3(10)) - int4(1);
_0_result = int4(2) * int4(1, 2, 3, 4);
_0_result = int4(12) / int4(1, 2, 3, 4);
_out->sk_FragColor.x = float((int4(12) / int4(1, 2, 3, 4)).y);
_out->sk_FragColor.x = all(int4(1) == int4(1)) ? 1.0 : -1.0;
_out->sk_FragColor.x = all(int4(1) == int4(2)) ? 2.0 : -2.0;
_out->sk_FragColor.x = all(int2(1) == int2(1, 1)) ? 3.0 : -3.0;
_out->sk_FragColor.x = all(int2(1, 1) == int2(1, 1)) ? 4.0 : -4.0;
_out->sk_FragColor.x = all(int2(1) == int2(1, 0)) ? 5.0 : -5.0;
_out->sk_FragColor.x = all(int4(1) == int4(int2(1), int2(1))) ? 6.0 : -6.0;
_out->sk_FragColor.x = all(int4(int3(1), 1) == int4(int2(1), int2(1))) ? 7.0 : -7.0;
_out->sk_FragColor.x = all(int4(int3(1), 1) == int4(int2(1), 1, 0)) ? 8.0 : -8.0;
_out->sk_FragColor.x = any(int2(1) != int2(1, 0)) ? 9.0 : -9.0;
_out->sk_FragColor.x = any(int4(1) != int4(int2(1), int2(1))) ? 10.0 : -10.0;
_0_result = int4(6, 7, 9, 11);
_0_result = int4(7, 9, 9, 9);
_0_result = int4(2, 4, 6, 8);
_0_result = int4(12, 6, 4, 3);
_out->sk_FragColor.x = 6.0;
_out->sk_FragColor.x = 1.0;
_out->sk_FragColor.x = -2.0;
_out->sk_FragColor.x = 3.0;
_out->sk_FragColor.x = 4.0;
_out->sk_FragColor.x = -5.0;
_out->sk_FragColor.x = 6.0;
_out->sk_FragColor.x = 7.0;
_out->sk_FragColor.x = -8.0;
_out->sk_FragColor.x = 9.0;
_out->sk_FragColor.x = -10.0;
_0_result = int4(int(sqrt(1.0)));
_0_result = int4(int(sqrt(2.0)));
_0_result = int4(0);