Add support for multi-element vector swizzles. Issue #17.
This commit adds support for swizzles like "foo.zy" (if "foo" is, for example, a float<3> type) as rvalues. (Still need support for swizzles as lvalues.)
This commit is contained in:
committed by
Matt Pharr
parent
98a2d69e72
commit
59036cdf5b
418
expr.cpp
418
expr.cpp
@@ -2820,6 +2820,288 @@ IndexExpr::Print() const {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// MemberExpr
|
||||
|
||||
/** Map one character ids to vector element numbers. Allow a few different
|
||||
conventions--xyzw, rgba, uv.
|
||||
*/
|
||||
static int
|
||||
lIdentifierToVectorElement(char id) {
|
||||
switch (id) {
|
||||
case 'x':
|
||||
case 'r':
|
||||
case 'u':
|
||||
return 0;
|
||||
case 'y':
|
||||
case 'g':
|
||||
case 'v':
|
||||
return 1;
|
||||
case 'z':
|
||||
case 'b':
|
||||
return 2;
|
||||
case 'w':
|
||||
case 'a':
|
||||
return 3;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
class StructMemberExpr : public MemberExpr
|
||||
{
|
||||
public:
|
||||
StructMemberExpr(Expr *e, const char *id, SourcePos p,
|
||||
SourcePos idpos, const StructType* structType);
|
||||
|
||||
const Type* GetType() const;
|
||||
|
||||
int getElementNumber() const;
|
||||
|
||||
private:
|
||||
const StructType* exprStructType;
|
||||
};
|
||||
|
||||
StructMemberExpr::StructMemberExpr(Expr *e, const char *id, SourcePos p,
|
||||
SourcePos idpos,
|
||||
const StructType* structType)
|
||||
: MemberExpr(e, id, p, idpos), exprStructType(structType) {
|
||||
}
|
||||
|
||||
const Type*
|
||||
StructMemberExpr::GetType() const {
|
||||
// It's a struct, and the result type is the element
|
||||
// type, possibly promoted to varying if the struct type / lvalue
|
||||
// is varying.
|
||||
const Type *elementType = exprStructType->GetElementType(identifier);
|
||||
if (!elementType)
|
||||
Error(identifierPos,
|
||||
"Element name \"%s\" not present in struct type \"%s\".%s",
|
||||
identifier.c_str(), exprStructType->GetString().c_str(),
|
||||
getCandidateNearMatches().c_str());
|
||||
|
||||
if (exprStructType->IsVaryingType())
|
||||
return elementType->GetAsVaryingType();
|
||||
else
|
||||
return elementType;
|
||||
}
|
||||
|
||||
int
|
||||
StructMemberExpr::getElementNumber() const {
|
||||
int elementNumber = exprStructType->GetElementNumber(identifier);
|
||||
if (elementNumber == -1)
|
||||
Error(identifierPos,
|
||||
"Element name \"%s\" not present in struct type \"%s\".%s",
|
||||
identifier.c_str(), exprStructType->GetString().c_str(),
|
||||
getCandidateNearMatches().c_str());
|
||||
return elementNumber;
|
||||
}
|
||||
|
||||
class VectorMemberExpr : public MemberExpr
|
||||
{
|
||||
public:
|
||||
VectorMemberExpr(Expr *e, const char *id, SourcePos p,
|
||||
SourcePos idpos, const VectorType* vectorType);
|
||||
|
||||
~VectorMemberExpr();
|
||||
|
||||
const Type* GetType() const;
|
||||
|
||||
llvm::Value* GetLValue(FunctionEmitContext* ctx) const;
|
||||
|
||||
llvm::Value* GetValue(FunctionEmitContext* ctx) const;
|
||||
|
||||
int getElementNumber() const;
|
||||
private:
|
||||
const VectorType* exprVectorType;
|
||||
const VectorType* memberType;
|
||||
};
|
||||
|
||||
VectorMemberExpr::VectorMemberExpr(Expr *e, const char *id, SourcePos p,
|
||||
SourcePos idpos,
|
||||
const VectorType* vectorType)
|
||||
: MemberExpr(e, id, p, idpos), exprVectorType(vectorType) {
|
||||
memberType = new VectorType(exprVectorType->GetElementType(),
|
||||
identifier.length());
|
||||
}
|
||||
|
||||
VectorMemberExpr::~VectorMemberExpr() {
|
||||
delete memberType;
|
||||
}
|
||||
|
||||
const Type*
|
||||
VectorMemberExpr::GetType() const {
|
||||
// For 1-element expressions, we have the base vector element
|
||||
// type. For n-element expressions, we have a shortvec type
|
||||
// with n > 1 elements. This can be changed when we get
|
||||
// type<1> -> type conversions.
|
||||
if (identifier.length() == 1) {
|
||||
return exprVectorType->GetElementType();
|
||||
} else {
|
||||
return memberType;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Value*
|
||||
VectorMemberExpr::GetLValue(FunctionEmitContext* ctx) const {
|
||||
if (identifier.length() == 1) {
|
||||
return MemberExpr::GetLValue(ctx);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Value*
|
||||
VectorMemberExpr::GetValue(FunctionEmitContext* ctx) const {
|
||||
if (identifier.length() == 1) {
|
||||
return MemberExpr::GetValue(ctx);
|
||||
} else {
|
||||
std::vector<int> indices;
|
||||
|
||||
for (size_t i = 0; i < identifier.size(); ++i) {
|
||||
int idx = lIdentifierToVectorElement(identifier[i]);
|
||||
if (idx == -1)
|
||||
Error(pos,
|
||||
"Invalid swizzle charcter '%c' in swizzle \"%s\".",
|
||||
identifier[i], identifier.c_str());
|
||||
|
||||
indices.push_back(idx);
|
||||
}
|
||||
|
||||
llvm::Value *basePtr = expr->GetLValue(ctx);
|
||||
if (basePtr == NULL) {
|
||||
assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
}
|
||||
llvm::Value *ltmp = ctx->AllocaInst(memberType->LLVMType(g->ctx),
|
||||
"vector_tmp");
|
||||
|
||||
ctx->SetDebugPos(pos);
|
||||
for (size_t i = 0; i < identifier.size(); ++i) {
|
||||
llvm::Value *ptmp =
|
||||
ctx->GetElementPtrInst(ltmp, 0, i, "new_offset");
|
||||
llvm::Value *initLValue =
|
||||
ctx->GetElementPtrInst(basePtr , 0,
|
||||
indices[i], "orig_offset");
|
||||
llvm::Value *initValue =
|
||||
ctx->LoadInst(initLValue, memberType->GetElementType(),
|
||||
"vec_element");
|
||||
ctx->StoreInst(initValue, ptmp);
|
||||
}
|
||||
|
||||
return ctx->LoadInst(ltmp, memberType, "swizzle_vec");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
VectorMemberExpr::getElementNumber() const {
|
||||
int elementNumber = lIdentifierToVectorElement(identifier[0]);
|
||||
if (elementNumber == -1)
|
||||
Error(pos, "Vector element identifier \"%s\" unknown.",
|
||||
identifier.c_str());
|
||||
return elementNumber;
|
||||
}
|
||||
|
||||
class ReferenceMemberExpr : public MemberExpr
|
||||
{
|
||||
public:
|
||||
ReferenceMemberExpr(Expr *e, const char *id, SourcePos p,
|
||||
SourcePos idpos, const ReferenceType* referenceType);
|
||||
|
||||
const Type* GetType() const;
|
||||
|
||||
int getElementNumber() const;
|
||||
|
||||
llvm::Value* GetLValue(FunctionEmitContext* ctx) const;
|
||||
|
||||
private:
|
||||
const ReferenceType* exprReferenceType;
|
||||
MemberExpr* dereferencedExpr;
|
||||
};
|
||||
|
||||
ReferenceMemberExpr::ReferenceMemberExpr(Expr *e, const char *id, SourcePos p,
|
||||
SourcePos idpos,
|
||||
const ReferenceType* referenceType)
|
||||
: MemberExpr(e, id, p, idpos), exprReferenceType(referenceType) {
|
||||
const Type* refTarget = exprReferenceType->GetReferenceTarget();
|
||||
const StructType* structType
|
||||
= dynamic_cast<const StructType *>(refTarget);
|
||||
const VectorType* vectorType
|
||||
= dynamic_cast<const VectorType *>(refTarget);
|
||||
|
||||
if (structType != NULL) {
|
||||
dereferencedExpr = new StructMemberExpr(e, id, p, idpos, structType);
|
||||
} else if (vectorType != NULL) {
|
||||
dereferencedExpr = new VectorMemberExpr(e, id, p, idpos, vectorType);
|
||||
} else {
|
||||
dereferencedExpr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const Type*
|
||||
ReferenceMemberExpr::GetType() const {
|
||||
if (dereferencedExpr == NULL) {
|
||||
Error(pos, "Can't access member of non-struct/vector type \"%s\".",
|
||||
exprReferenceType->GetString().c_str());
|
||||
return NULL;
|
||||
} else {
|
||||
return dereferencedExpr->GetType();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ReferenceMemberExpr::getElementNumber() const {
|
||||
if (dereferencedExpr == NULL) {
|
||||
// FIXME: I think we shouldn't ever get here and that
|
||||
// typechecking should have caught this case
|
||||
return -1;
|
||||
} else {
|
||||
return dereferencedExpr->getElementNumber();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Value*
|
||||
ReferenceMemberExpr::GetLValue(FunctionEmitContext* ctx) const {
|
||||
if (dereferencedExpr == NULL) {
|
||||
// FIXME: again I think typechecking should have caught this
|
||||
Error(pos, "Can't access member of non-struct/vector type \"%s\".",
|
||||
exprReferenceType->GetString().c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//FIXME: Minor Code-dup...this is the same as the base, except
|
||||
// llvm::Value *basePtr = expr->GetLValue instead of expr->getValue
|
||||
llvm::Value *basePtr = expr->GetValue(ctx);
|
||||
if (!basePtr)
|
||||
return NULL;
|
||||
|
||||
int elementNumber = getElementNumber();
|
||||
if (elementNumber == -1)
|
||||
return NULL;
|
||||
|
||||
ctx->SetDebugPos(pos);
|
||||
return ctx->GetElementPtrInst(basePtr, 0, elementNumber);
|
||||
}
|
||||
|
||||
|
||||
MemberExpr*
|
||||
MemberExpr::create(Expr *e, const char *id, SourcePos p, SourcePos idpos) {
|
||||
const Type* exprType;
|
||||
if (e == NULL || (exprType = e->GetType()) == NULL)
|
||||
return new MemberExpr(e, id, p, idpos);
|
||||
|
||||
const StructType* structType = dynamic_cast<const StructType*>(exprType);
|
||||
if (structType != NULL)
|
||||
return new StructMemberExpr(e, id, p, idpos, structType);
|
||||
|
||||
const VectorType* vectorType = dynamic_cast<const VectorType*>(exprType);
|
||||
if (vectorType != NULL)
|
||||
return new VectorMemberExpr(e, id, p, idpos, vectorType);
|
||||
|
||||
const ReferenceType* referenceType = dynamic_cast<const ReferenceType*>(exprType);
|
||||
if (referenceType != NULL)
|
||||
return new ReferenceMemberExpr(e, id, p, idpos, referenceType);
|
||||
|
||||
return new MemberExpr(e, id, p, idpos);
|
||||
}
|
||||
|
||||
MemberExpr::MemberExpr(Expr *e, const char *id, SourcePos p, SourcePos idpos)
|
||||
: Expr(p), identifierPos(idpos) {
|
||||
expr = e;
|
||||
@@ -2861,48 +3143,7 @@ MemberExpr::GetValue(FunctionEmitContext *ctx) const {
|
||||
|
||||
const Type *
|
||||
MemberExpr::GetType() const {
|
||||
if (!expr)
|
||||
return NULL;
|
||||
|
||||
const Type *exprType = expr->GetType();
|
||||
if (!exprType)
|
||||
return NULL;
|
||||
|
||||
const StructType *structType = dynamic_cast<const StructType *>(exprType);
|
||||
const VectorType *vectorType = dynamic_cast<const VectorType *>(exprType);
|
||||
if (!structType && !vectorType) {
|
||||
const ReferenceType *referenceType =
|
||||
dynamic_cast<const ReferenceType *>(exprType);
|
||||
const Type *refTarget = (referenceType == NULL) ? NULL :
|
||||
referenceType->GetReferenceTarget();
|
||||
if ((structType = dynamic_cast<const StructType *>(refTarget)) == NULL &&
|
||||
(vectorType = dynamic_cast<const VectorType *>(refTarget)) == NULL) {
|
||||
Error(pos, "Can't access member of non-struct/vector type \"%s\".",
|
||||
exprType->GetString().c_str());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (vectorType != NULL)
|
||||
// only one-element vector selection is supported for now (i.e. no
|
||||
// swizzling "foo.xxy"), so the result type is always just the
|
||||
// element type.
|
||||
return vectorType->GetElementType();
|
||||
else {
|
||||
// Otherwise it's a struct, and the result type is the element
|
||||
// type, possibly promoted to varying if the struct type / lvalue
|
||||
// is varying.
|
||||
const Type *elementType = structType->GetElementType(identifier);
|
||||
if (!elementType)
|
||||
Error(identifierPos, "Element name \"%s\" not present in struct type \"%s\".%s",
|
||||
identifier.c_str(), structType->GetString().c_str(),
|
||||
getCandidateNearMatches().c_str());
|
||||
|
||||
if (exprType->IsVaryingType())
|
||||
return elementType->GetAsVaryingType();
|
||||
else
|
||||
return elementType;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -2912,106 +3153,23 @@ MemberExpr::GetBaseSymbol() const {
|
||||
}
|
||||
|
||||
|
||||
/** Map one character ids to vector element numbers. Allow a few different
|
||||
conventions--xyzw, rgba, uv.
|
||||
*/
|
||||
static int
|
||||
lIdentifierToVectorElement(char id) {
|
||||
switch (id) {
|
||||
case 'x':
|
||||
case 'r':
|
||||
case 'u':
|
||||
return 0;
|
||||
case 'y':
|
||||
case 'g':
|
||||
case 'v':
|
||||
return 1;
|
||||
case 'z':
|
||||
case 'b':
|
||||
return 2;
|
||||
case 'w':
|
||||
case 'a':
|
||||
return 3;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
MemberExpr::getElementNumber() const {
|
||||
const Type *exprType;
|
||||
if (!expr || ((exprType = expr->GetType()) == NULL))
|
||||
return -1;
|
||||
|
||||
const StructType *structType = dynamic_cast<const StructType *>(exprType);
|
||||
const VectorType *vectorType = dynamic_cast<const VectorType *>(exprType);
|
||||
if (!structType && !vectorType) {
|
||||
const ReferenceType *referenceType =
|
||||
dynamic_cast<const ReferenceType *>(exprType);
|
||||
const Type *refTarget = (referenceType == NULL) ? NULL :
|
||||
referenceType->GetReferenceTarget() ;
|
||||
if ((structType = dynamic_cast<const StructType *>(refTarget)) == NULL &&
|
||||
(vectorType = dynamic_cast<const VectorType *>(refTarget)) == NULL)
|
||||
// FIXME: I think we shouldn't ever get here and that
|
||||
// typechecking should have caught this case
|
||||
return -1;
|
||||
}
|
||||
|
||||
int elementNumber = -1;
|
||||
if (vectorType) {
|
||||
if (identifier.size() != 1) {
|
||||
Error(pos, "Only single-character vector element accessors are currently "
|
||||
"supported--\"%s\" is invalid. Sorry.", identifier.c_str());
|
||||
}
|
||||
else {
|
||||
elementNumber = lIdentifierToVectorElement(identifier[0]);
|
||||
if (elementNumber == -1)
|
||||
Error(pos, "Vector element identifier \"%s\" unknown.",
|
||||
identifier.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
elementNumber = structType->GetElementNumber(identifier);
|
||||
if (elementNumber == -1)
|
||||
Error(identifierPos, "Element name \"%s\" not present in struct type \"%s\".%s",
|
||||
identifier.c_str(), structType->GetString().c_str(),
|
||||
getCandidateNearMatches().c_str());
|
||||
}
|
||||
return elementNumber;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
llvm::Value *
|
||||
MemberExpr::GetLValue(FunctionEmitContext *ctx) const {
|
||||
//This kindof feels like magic, but this functionality
|
||||
// will have to be overridden in VectorMemberExpr when
|
||||
// we support multi-swizzle.
|
||||
const Type *exprType;
|
||||
if (!expr || ((exprType = expr->GetType()) == NULL))
|
||||
return NULL;
|
||||
|
||||
ctx->SetDebugPos(pos);
|
||||
const StructType *structType = dynamic_cast<const StructType *>(exprType);
|
||||
const VectorType *vectorType = dynamic_cast<const VectorType *>(exprType);
|
||||
llvm::Value *basePtr = NULL;
|
||||
if (structType || vectorType)
|
||||
basePtr = expr->GetLValue(ctx);
|
||||
else {
|
||||
const ReferenceType *referenceType = dynamic_cast<const ReferenceType *>(exprType);
|
||||
// FIXME: store structType and vectorType as members, or do all
|
||||
// this in a separate function? This code to figure out
|
||||
// struct/vectorType is replicated a bunch of times in
|
||||
// MemberExpr...
|
||||
const Type *refTarget = (referenceType == NULL) ? NULL :
|
||||
referenceType->GetReferenceTarget() ;
|
||||
if ((structType = dynamic_cast<const StructType *>(refTarget)) == NULL &&
|
||||
(vectorType = dynamic_cast<const VectorType *>(refTarget)) == NULL) {
|
||||
// FIXME: again I think typechecking should have caught this
|
||||
Error(pos, "Can't access member of non-struct/vector type \"%s\".",
|
||||
exprType->GetString().c_str());
|
||||
return NULL;
|
||||
}
|
||||
basePtr = expr->GetValue(ctx);
|
||||
}
|
||||
llvm::Value *basePtr = expr->GetLValue(ctx);
|
||||
if (!basePtr)
|
||||
return NULL;
|
||||
|
||||
|
||||
23
expr.h
23
expr.h
@@ -292,23 +292,28 @@ private:
|
||||
|
||||
|
||||
/** @brief Expression representing member selection ("foo.bar").
|
||||
*
|
||||
* This will also be overloaded to deal with swizzles.
|
||||
*/
|
||||
class MemberExpr : public Expr {
|
||||
public:
|
||||
static MemberExpr* create(Expr *expr, const char *identifier,
|
||||
SourcePos pos, SourcePos identifierPos);
|
||||
|
||||
MemberExpr(Expr *expr, const char *identifier, SourcePos pos,
|
||||
SourcePos identifierPos);
|
||||
|
||||
llvm::Value *GetValue(FunctionEmitContext *ctx) const;
|
||||
llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
|
||||
const Type *GetType() const;
|
||||
Symbol *GetBaseSymbol() const;
|
||||
void Print() const;
|
||||
Expr *Optimize();
|
||||
Expr *TypeCheck();
|
||||
virtual llvm::Value *GetValue(FunctionEmitContext *ctx) const;
|
||||
virtual llvm::Value *GetLValue(FunctionEmitContext *ctx) const;
|
||||
virtual const Type *GetType() const;
|
||||
virtual Symbol *GetBaseSymbol() const;
|
||||
virtual void Print() const;
|
||||
virtual Expr *Optimize();
|
||||
virtual Expr *TypeCheck();
|
||||
virtual int getElementNumber() const;
|
||||
|
||||
private:
|
||||
protected:
|
||||
std::string getCandidateNearMatches() const;
|
||||
int getElementNumber() const;
|
||||
|
||||
Expr *expr;
|
||||
std::string identifier;
|
||||
|
||||
1
lex.ll
1
lex.ll
@@ -72,6 +72,7 @@ FLOAT_NUMBER (([0-9]+|(([0-9]+\.[0-9]*[fF]?)|(\.[0-9]+)))([eE][-+]?[0-9]+)?[fF]?
|
||||
HEX_FLOAT_NUMBER (0x[01](\.[0-9a-fA-F]*)?p[-+]?[0-9]+[fF]?)
|
||||
|
||||
IDENT [a-zA-Z_][a-zA-Z_0-9]*
|
||||
ZO_SWIZZLE ([01]+[w-z]+)+|([01]+[rgba]+)+|([01]+[uv]+)+
|
||||
|
||||
%%
|
||||
"/*" { lCComment(yylloc); }
|
||||
|
||||
2
parse.yy
2
parse.yy
@@ -269,7 +269,7 @@ postfix_expression
|
||||
| TOKEN_LAUNCH '<' postfix_expression '(' ')' '>'
|
||||
{ $$ = new FunctionCallExpr($3, new ExprList(@3), @3, true); }
|
||||
| postfix_expression '.' TOKEN_IDENTIFIER
|
||||
{ $$ = new MemberExpr($1, yytext, @1, @3); }
|
||||
{ $$ = MemberExpr::create($1, yytext, @1, @3); }
|
||||
/* | postfix_expression TOKEN_PTR_OP TOKEN_IDENTIFIER
|
||||
{ UNIMPLEMENTED }
|
||||
*/
|
||||
|
||||
15
tests/swizzle-1.ispc
Normal file
15
tests/swizzle-1.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_v(uniform float RET[]) {
|
||||
float<3> a = {1,2,3};
|
||||
float<3> b = a.zxy;
|
||||
|
||||
RET[programIndex] = b.x;
|
||||
}
|
||||
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 3;
|
||||
}
|
||||
15
tests/swizzle-2.ispc
Normal file
15
tests/swizzle-2.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_v(uniform float RET[]) {
|
||||
float<3> a = {1,10,100};
|
||||
float<3> b = a.zxy;
|
||||
|
||||
RET[programIndex] = b.x + 2*b.y + 3*b.z;
|
||||
}
|
||||
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 132;
|
||||
}
|
||||
15
tests/swizzle-3.ispc
Normal file
15
tests/swizzle-3.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_v(uniform float RET[]) {
|
||||
float<3> a = {1,10,100};
|
||||
float<6> b = a.zxyyxz;
|
||||
|
||||
RET[programIndex] = b.x + 2*b.y + 3*b.z - 3*b[3] - 2*b[4] - b[5];
|
||||
}
|
||||
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 0;
|
||||
}
|
||||
15
tests/swizzle-4.ispc
Normal file
15
tests/swizzle-4.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_v(uniform float RET[]) {
|
||||
float<3> a = {1,2,3};
|
||||
float<2> b = a.xy - a.uv;
|
||||
|
||||
RET[programIndex] = b.x + 2*b.y;
|
||||
}
|
||||
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 0;
|
||||
}
|
||||
15
tests/swizzle-5.ispc
Normal file
15
tests/swizzle-5.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_v(uniform float RET[]) {
|
||||
float<3> a = {1,2,3};
|
||||
float<3> b = a.rgb;
|
||||
|
||||
RET[programIndex] = b.x + 2*b.y + 3*b.z;
|
||||
}
|
||||
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 14;
|
||||
}
|
||||
18
tests/swizzle-6.ispc
Normal file
18
tests/swizzle-6.ispc
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_v(uniform float RET[]) {
|
||||
float<3> a = {1,2,3};
|
||||
float<3> b1 = a.yzx;
|
||||
float<3> b2 = b1.yzx;
|
||||
float<3> b3 = b2.yzx;
|
||||
float<3> b = b3 - a;
|
||||
|
||||
RET[programIndex] = b.x + 2*b.y + 3*b.z;
|
||||
}
|
||||
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user