Restored unsized array support to SkSL
This is a prerequisite for compute shaders. As of this CL, there isn't yet a way to use unsized arrays, as it is a compute-only feature and compute shaders are coming in a followup CL, but this adds the basic framework and error tests. Change-Id: I390c0961e324dd474474563bf9a8f6b34c9552a9 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/538900 Reviewed-by: John Stiles <johnstiles@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
1e5eab37e1
commit
9583759bbd
@ -20,13 +20,29 @@ sksl_error_tests = [
|
||||
"/sksl/errors/ArraySplitDimensionsInFuncDecl.rts",
|
||||
"/sksl/errors/ArraySplitDimensionsInStruct.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensions.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsUnsized1.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsUnsized2.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInFuncBody.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInFuncBodyUnsized1.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInFuncBodyUnsized2.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInFuncDecl.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInFuncDeclUnsized1.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInFuncDeclUnsized2.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInStruct.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInStructUnsized1.rts",
|
||||
"/sksl/errors/ArrayTooManyDimensionsInStructUnsized2.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensions.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsUnsized1.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsUnsized2.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncBody.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncBodyUnsized1.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncBodyUnsized2.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncDecl.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncDeclUnsized1.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInFuncDeclUnsized2.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInStruct.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInStructUnsized1.rts",
|
||||
"/sksl/errors/ArrayTypeTooManyDimensionsInStructUnsized2.rts",
|
||||
"/sksl/errors/ArrayUnspecifiedDimensions.rts",
|
||||
"/sksl/errors/AssignmentTypeMismatch.rts",
|
||||
"/sksl/errors/BadCaps.sksl",
|
||||
|
@ -181,6 +181,7 @@ private:
|
||||
|
||||
friend DSLType Array(const DSLType& base, int count, Position pos);
|
||||
friend DSLType Struct(std::string_view name, SkSpan<DSLField> fields, Position pos);
|
||||
friend DSLType UnsizedArray(const DSLType& base, Position pos);
|
||||
friend class DSLCore;
|
||||
friend class DSLFunction;
|
||||
friend class DSLVarBase;
|
||||
@ -228,6 +229,8 @@ MATRIX_TYPE(Half)
|
||||
|
||||
DSLType Array(const DSLType& base, int count, Position pos = {});
|
||||
|
||||
DSLType UnsizedArray(const DSLType& base, Position pos = {});
|
||||
|
||||
class DSLField {
|
||||
public:
|
||||
DSLField(const DSLType type, std::string_view name,
|
||||
|
@ -43,7 +43,7 @@ array size out of bounds
|
||||
array size must be an integer
|
||||
array size must be an integer
|
||||
array size must be an integer
|
||||
expected array dimension
|
||||
unsized arrays are not permitted here
|
||||
integer is out of range for type 'int': 4000000000
|
||||
integer is out of range for type 'int': 100000002004087734272
|
||||
*%%*/
|
||||
|
@ -0,0 +1,5 @@
|
||||
void func() { float x[][2]; }
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
void func() { float x[2][]; }
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
void func(float x[][2]) {}
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
void func(float x[2][]) {}
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
struct S { float x[][2]; };
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
struct S { float x[2][]; };
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
5
resources/sksl/errors/ArrayTooManyDimensionsUnsized1.rts
Normal file
5
resources/sksl/errors/ArrayTooManyDimensionsUnsized1.rts
Normal file
@ -0,0 +1,5 @@
|
||||
float x[][2];
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
5
resources/sksl/errors/ArrayTooManyDimensionsUnsized2.rts
Normal file
5
resources/sksl/errors/ArrayTooManyDimensionsUnsized2.rts
Normal file
@ -0,0 +1,5 @@
|
||||
float x[2][];
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
void func() { float[][2] x; }
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
void func() { float[2][] x; }
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
void func(float[][2] x) {}
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
void func(float[2][] x) {}
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
struct S { float[][2] x; };
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
struct S { float[2][] x; };
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
float[][2] x;
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -0,0 +1,5 @@
|
||||
float[2][] x;
|
||||
|
||||
/*%%*
|
||||
unsized arrays are not permitted here
|
||||
*%%*/
|
@ -5,7 +5,7 @@ int arrBool[true];
|
||||
int unsized_in_expression() { return int[](0)[0]; }
|
||||
|
||||
/*%%*
|
||||
expected array dimension
|
||||
unsized arrays are not permitted here
|
||||
array size must be an integer
|
||||
array size must be an integer
|
||||
missing index in '[]'
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "src/sksl/dsl/priv/DSL_priv.h"
|
||||
#include "src/sksl/ir/SkSLExpression.h"
|
||||
#include "src/sksl/ir/SkSLProgram.h"
|
||||
#include "src/sksl/ir/SkSLType.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
@ -461,6 +462,11 @@ bool DSLParser::functionDeclarationEnd(Position start,
|
||||
}
|
||||
|
||||
bool DSLParser::arraySize(SKSL_INT* outResult) {
|
||||
Token next = this->peek();
|
||||
if (next.fKind == Token::Kind::TK_RBRACKET) {
|
||||
this->error(this->position(next), "unsized arrays are not permitted here");
|
||||
return true;
|
||||
}
|
||||
DSLExpression sizeExpr = this->expression();
|
||||
if (!sizeExpr.hasValue()) {
|
||||
return false;
|
||||
@ -492,7 +498,7 @@ bool DSLParser::parseArrayDimensions(Position pos, DSLType* type) {
|
||||
Token next;
|
||||
while (this->checkNext(Token::Kind::TK_LBRACKET, &next)) {
|
||||
if (this->checkNext(Token::Kind::TK_RBRACKET)) {
|
||||
this->error(this->rangeFrom(next), "expected array dimension");
|
||||
this->error(this->rangeFrom(pos), "unsized arrays are not permitted here");
|
||||
} else {
|
||||
SKSL_INT size;
|
||||
if (!this->arraySize(&size)) {
|
||||
@ -967,17 +973,17 @@ DSLType DSLParser::type(DSLModifiers* modifiers) {
|
||||
return DSLType(nullptr);
|
||||
}
|
||||
DSLType result(this->text(type), modifiers, this->position(type));
|
||||
while (this->checkNext(Token::Kind::TK_LBRACKET)) {
|
||||
if (this->peek().fKind != Token::Kind::TK_RBRACKET) {
|
||||
Token bracket;
|
||||
while (this->checkNext(Token::Kind::TK_LBRACKET, &bracket)) {
|
||||
if (this->checkNext(Token::Kind::TK_RBRACKET)) {
|
||||
this->error(this->rangeFrom(bracket), "unsized arrays are not permitted here");
|
||||
} else {
|
||||
SKSL_INT size;
|
||||
if (!this->arraySize(&size)) {
|
||||
return DSLType(nullptr);
|
||||
}
|
||||
this->expect(Token::Kind::TK_RBRACKET, "']'");
|
||||
result = Array(result, size, this->rangeFrom(type));
|
||||
} else {
|
||||
this->error(this->peek(), "expected array dimension");
|
||||
this->expect(Token::Kind::TK_RBRACKET, "']'");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -1023,7 +1029,7 @@ bool DSLParser::interfaceBlock(const dsl::DSLModifiers& modifiers) {
|
||||
}
|
||||
actualType = Array(std::move(actualType), size, this->position(typeName));
|
||||
} else {
|
||||
this->error(sizeToken, "unsized arrays are not permitted");
|
||||
this->error(sizeToken, "unsized arrays are not permitted here");
|
||||
}
|
||||
this->expect(Token::Kind::TK_RBRACKET, "']'");
|
||||
}
|
||||
|
@ -275,6 +275,11 @@ DSLType Array(const DSLType& base, int count, Position pos) {
|
||||
return DSLType(ThreadContext::SymbolTable()->addArrayDimension(&base.skslType(), count), pos);
|
||||
}
|
||||
|
||||
DSLType UnsizedArray(const DSLType& base, Position pos) {
|
||||
return ThreadContext::SymbolTable()->addArrayDimension(&base.skslType(),
|
||||
SkSL::Type::kUnsizedArray);
|
||||
}
|
||||
|
||||
DSLType Struct(std::string_view name, SkSpan<DSLField> fields, Position pos) {
|
||||
std::vector<SkSL::Type::Field> skslFields;
|
||||
skslFields.reserve(fields.size());
|
||||
|
@ -20,10 +20,13 @@ namespace SkSL {
|
||||
|
||||
static bool index_out_of_range(const Context& context, Position pos, SKSL_INT index,
|
||||
const Expression& base) {
|
||||
if (index >= 0 && index < base.type().columns()) {
|
||||
return false;
|
||||
if (index >= 0) {
|
||||
if (base.type().columns() == Type::kUnsizedArray) {
|
||||
return false;
|
||||
} else if (index < base.type().columns()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
context.fErrors->error(pos, "index " + std::to_string(index) + " out of range for '" +
|
||||
base.type().displayName() + "'");
|
||||
return true;
|
||||
|
@ -126,8 +126,7 @@ public:
|
||||
: INHERITED(name, abbrev, kTypeKind)
|
||||
, fComponentType(componentType)
|
||||
, fCount(count) {
|
||||
// Only allow explicitly-sized arrays.
|
||||
SkASSERT(count > 0);
|
||||
SkASSERT(count > 0 || count == kUnsizedArray);
|
||||
// Disallow multi-dimensional arrays.
|
||||
SkASSERT(!componentType.is<ArrayType>());
|
||||
}
|
||||
@ -157,6 +156,7 @@ public:
|
||||
}
|
||||
|
||||
size_t slotCount() const override {
|
||||
SkASSERT(fCount != kUnsizedArray);
|
||||
SkASSERT(fCount > 0);
|
||||
return fCount * fComponentType.slotCount();
|
||||
}
|
||||
@ -522,6 +522,9 @@ private:
|
||||
|
||||
std::string Type::getArrayName(int arraySize) const {
|
||||
std::string_view name = this->name();
|
||||
if (arraySize == kUnsizedArray) {
|
||||
return String::printf("%.*s[]", (int)name.size(), name.data());
|
||||
}
|
||||
return String::printf("%.*s[%d]", (int)name.size(), name.data(), arraySize);
|
||||
}
|
||||
|
||||
@ -965,23 +968,30 @@ bool Type::checkForOutOfRangeLiteral(const Context& context, double value, Posit
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::checkIfUsableInArray(const Context& context, Position arrayPos) const {
|
||||
if (this->isArray()) {
|
||||
context.fErrors->error(arrayPos, "multi-dimensional arrays are not supported");
|
||||
return false;
|
||||
}
|
||||
if (this->isVoid()) {
|
||||
context.fErrors->error(arrayPos, "type 'void' may not be used in an array");
|
||||
return false;
|
||||
}
|
||||
if (this->isOpaque()) {
|
||||
context.fErrors->error(arrayPos, "opaque type '" + std::string(this->name()) +
|
||||
"' may not be used in an array");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SKSL_INT Type::convertArraySize(const Context& context, Position arrayPos,
|
||||
std::unique_ptr<Expression> size) const {
|
||||
size = context.fTypes.fInt->coerceExpression(std::move(size), context);
|
||||
if (!size) {
|
||||
return 0;
|
||||
}
|
||||
if (this->isArray()) {
|
||||
context.fErrors->error(arrayPos, "multi-dimensional arrays are not supported");
|
||||
return 0;
|
||||
}
|
||||
if (this->isVoid()) {
|
||||
context.fErrors->error(arrayPos, "type 'void' may not be used in an array");
|
||||
return 0;
|
||||
}
|
||||
if (this->isOpaque()) {
|
||||
context.fErrors->error(arrayPos, "opaque type '" + std::string(this->name()) +
|
||||
"' may not be used in an array");
|
||||
if (!this->checkIfUsableInArray(context, arrayPos)) {
|
||||
return 0;
|
||||
}
|
||||
SKSL_INT count;
|
||||
|
@ -58,7 +58,8 @@ class Type : public Symbol {
|
||||
public:
|
||||
inline static constexpr Kind kSymbolKind = Kind::kType;
|
||||
inline static constexpr int kMaxAbbrevLength = 3;
|
||||
|
||||
// Represents unspecified array dimensions, as in `int[]`.
|
||||
inline static constexpr int kUnsizedArray = -1;
|
||||
struct Field {
|
||||
Field(Position pos, Modifiers modifiers, std::string_view name, const Type* type)
|
||||
: fPosition(pos)
|
||||
@ -106,7 +107,7 @@ public:
|
||||
|
||||
Type(const Type& other) = delete;
|
||||
|
||||
/** Creates an array type. */
|
||||
/** Creates an array type. `columns` may be kUnsizedArray. */
|
||||
static std::unique_ptr<Type> MakeArrayType(std::string_view name, const Type& componentType,
|
||||
int columns);
|
||||
|
||||
@ -526,9 +527,14 @@ public:
|
||||
/** Checks if `value` can fit in this type. The type must be scalar. */
|
||||
bool checkForOutOfRangeLiteral(const Context& context, double value, Position pos) const;
|
||||
|
||||
/**
|
||||
* Reports errors and returns false if this type cannot be used as the base type for an array.
|
||||
*/
|
||||
bool checkIfUsableInArray(const Context& context, Position arrayPos) const;
|
||||
|
||||
/**
|
||||
* Verifies that the expression is a valid constant array size for this type. Returns the array
|
||||
* size, or zero if the expression isn't a valid literal value.
|
||||
* size, or reports errors and returns zero if the expression isn't a valid literal value.
|
||||
*/
|
||||
SKSL_INT convertArraySize(const Context& context, Position arrayPos,
|
||||
std::unique_ptr<Expression> size) const;
|
||||
|
@ -42,6 +42,9 @@ std::unique_ptr<Variable> Variable::Convert(const Context& context, Position pos
|
||||
if (!context.fConfig->fIsBuiltinCode && skstd::starts_with(name, '$')) {
|
||||
context.fErrors->error(namePos, "name '" + std::string(name) + "' is reserved");
|
||||
}
|
||||
if (baseType->isArray() && baseType->columns() == Type::kUnsizedArray) {
|
||||
context.fErrors->error(pos, "unsized arrays are not permitted here");
|
||||
}
|
||||
|
||||
return Make(context, pos, modifiersPos, modifiers, baseType, name, isArray,
|
||||
std::move(arraySize), storage);
|
||||
|
@ -60,9 +60,9 @@ void g2() { float x[false]; }
|
||||
error: 20: array size must be an integer
|
||||
void h2() { float x[int2(2, 2)]; }
|
||||
^^^^^^^^^^
|
||||
error: 21: expected array dimension
|
||||
error: 21: unsized arrays are not permitted here
|
||||
void i2() { float x[]; }
|
||||
^^
|
||||
^^^^^^^^^
|
||||
error: 22: integer is out of range for type 'int': 4000000000
|
||||
void j2() { float x[int3(4000000000)]; }
|
||||
^^^^^^^^^^
|
||||
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
void func() { float x[][2]; }
|
||||
^^^^^^^^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
void func() { float x[2][]; }
|
||||
^^^^^^^^^^^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
void func(float x[][2]) {}
|
||||
^^^^^^^^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
void func(float x[2][]) {}
|
||||
^^^^^^^^^^^^
|
||||
1 error
|
@ -0,0 +1,9 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
struct S { float x[][2]; };
|
||||
^
|
||||
error: 1: multi-dimensional arrays are not supported
|
||||
struct S { float x[][2]; };
|
||||
^^^^^^^^^^^^
|
||||
2 errors
|
@ -0,0 +1,9 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
struct S { float x[2][]; };
|
||||
^
|
||||
error: 1: multi-dimensional arrays are not supported
|
||||
struct S { float x[2][]; };
|
||||
^^^^^^^^^^^^
|
||||
2 errors
|
6
tests/sksl/errors/ArrayTooManyDimensionsUnsized1.glsl
Normal file
6
tests/sksl/errors/ArrayTooManyDimensionsUnsized1.glsl
Normal file
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
float x[][2];
|
||||
^^^^^^^^^
|
||||
1 error
|
6
tests/sksl/errors/ArrayTooManyDimensionsUnsized2.glsl
Normal file
6
tests/sksl/errors/ArrayTooManyDimensionsUnsized2.glsl
Normal file
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
float x[2][];
|
||||
^^^^^^^^^^^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
void func() { float[][2] x; }
|
||||
^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
void func() { float[2][] x; }
|
||||
^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
void func(float[][2] x) {}
|
||||
^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
void func(float[2][] x) {}
|
||||
^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
struct S { float[][2] x; };
|
||||
^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
struct S { float[2][] x; };
|
||||
^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
float[][2] x;
|
||||
^^
|
||||
1 error
|
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: unsized arrays are not permitted here
|
||||
float[2][] x;
|
||||
^^
|
||||
1 error
|
@ -1,8 +1,8 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: expected array dimension
|
||||
error: 1: unsized arrays are not permitted here
|
||||
int arrUnsized[];
|
||||
^^
|
||||
^^^^^^^^^^^^^^^^
|
||||
error: 2: array size must be an integer
|
||||
int arrFloat[1.];
|
||||
^^
|
||||
|
@ -1,6 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: expected expression, but found ']'
|
||||
error: 1: unsized arrays are not permitted here
|
||||
T { int x; } f[];
|
||||
^
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 1: expected expression, but found ']'
|
||||
error: 1: unsized arrays are not permitted here
|
||||
k{int z;}m[];void main(){}
|
||||
^
|
||||
1 error
|
||||
|
Loading…
Reference in New Issue
Block a user