diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 85e6eeb71378..05238f906234 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -23,6 +23,8 @@ #include "llvm/ADT/APFloat.h" #include +class llvm::Constant; + namespace clang { class IdentifierInfo; class Selector; @@ -701,11 +703,6 @@ class ExtVectorElementExpr : public Expr { IdentifierInfo &Accessor; SourceLocation AccessorLoc; public: - enum ElementType { - Point, // xywz - Color, // rgba - Texture // stpq - }; ExtVectorElementExpr(QualType ty, Expr *base, IdentifierInfo &accessor, SourceLocation loc) : Expr(ExtVectorElementExprClass, ty), @@ -719,25 +716,18 @@ public: /// getNumElements - Get the number of components being selected. unsigned getNumElements() const; - /// getElementType - Determine whether the components of this access are - /// "point" "color" or "texture" elements. - ElementType getElementType() const; - /// containsDuplicateElements - Return true if any element access is /// repeated. bool containsDuplicateElements() const; - /// getEncodedElementAccess - Encode the elements accessed into a bit vector. - /// The encoding currently uses 2-bit bitfields, but clients should use the - /// accessors below to access them. - /// - unsigned getEncodedElementAccess() const; + /// getEncodedElementAccess - Encode the elements accessed into an llvm + /// aggregate Constant of ConstantInt(s). + llvm::Constant *getEncodedElementAccess() const; /// getAccessedFieldNo - Given an encoded value and a result number, return /// the input field number being accessed. - static unsigned getAccessedFieldNo(unsigned Idx, unsigned EncodedVal) { - return (EncodedVal >> (Idx*2)) & 3; - } + static unsigned getAccessedFieldNo(unsigned Idx, + const llvm::Constant *Elts); virtual SourceRange getSourceRange() const { return SourceRange(getBase()->getLocStart(), AccessorLoc); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 90b8530339c2..61c21b067569 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -16,6 +16,8 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -1035,27 +1037,12 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const { } unsigned ExtVectorElementExpr::getNumElements() const { - return strlen(Accessor.getName()); + if (const VectorType *VT = getType()->getAsVectorType()) + return VT->getNumElements(); + return 1; } - -/// getComponentType - Determine whether the components of this access are -/// "point" "color" or "texture" elements. -ExtVectorElementExpr::ElementType -ExtVectorElementExpr::getElementType() const { - // derive the component type, no need to waste space. - const char *compStr = Accessor.getName(); - - if (ExtVectorType::getPointAccessorIdx(*compStr) != -1) return Point; - if (ExtVectorType::getColorAccessorIdx(*compStr) != -1) return Color; - - assert(ExtVectorType::getTextureAccessorIdx(*compStr) != -1 && - "getComponentType(): Illegal accessor"); - return Texture; -} - -/// containsDuplicateElements - Return true if any element access is -/// repeated. +/// containsDuplicateElements - Return true if any element access is repeated. bool ExtVectorElementExpr::containsDuplicateElements() const { const char *compStr = Accessor.getName(); unsigned length = strlen(compStr); @@ -1069,20 +1056,42 @@ bool ExtVectorElementExpr::containsDuplicateElements() const { return false; } -/// getEncodedElementAccess - We encode fields with two bits per component. -unsigned ExtVectorElementExpr::getEncodedElementAccess() const { +/// getEncodedElementAccess - We encode the fields as a llvm ConstantArray. +llvm::Constant *ExtVectorElementExpr::getEncodedElementAccess() const { const char *compStr = Accessor.getName(); - unsigned length = getNumElements(); + llvm::SmallVector Indices; + + bool isHi = !strcmp(compStr, "hi"); + bool isLo = !strcmp(compStr, "lo"); + bool isEven = !strcmp(compStr, "e"); + bool isOdd = !strcmp(compStr, "o"); + + for (unsigned i = 0, e = getNumElements(); i != e; ++i) { + uint64_t Index; + + if (isHi) + Index = e + i; + else if (isLo) + Index = i; + else if (isEven) + Index = 2 * i; + else if (isOdd) + Index = 2 * i + 1; + else + Index = ExtVectorType::getAccessorIdx(compStr[i]); - unsigned Result = 0; - - while (length--) { - Result <<= 2; - int Idx = ExtVectorType::getAccessorIdx(compStr[length]); - assert(Idx != -1 && "Invalid accessor letter"); - Result |= Idx; + Indices.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, Index)); } - return Result; + return llvm::ConstantVector::get(&Indices[0], Indices.size()); +} + +unsigned +ExtVectorElementExpr::getAccessedFieldNo(unsigned Idx, + const llvm::Constant *Elts) { + if (isa(Elts)) + return 0; + + return cast(Elts->getOperand(Idx))->getZExtValue(); } // constructor for instance messages. diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 3c1ab740b23a..043cfa1d507d 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -182,13 +182,13 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV, QualType ExprType) { llvm::Value *Vec = Builder.CreateLoad(LV.getExtVectorAddr(), "tmp"); - unsigned EncFields = LV.getExtVectorElts(); + const llvm::Constant *Elts = LV.getExtVectorElts(); // If the result of the expression is a non-vector type, we must be // extracting a single element. Just codegen as an extractelement. const VectorType *ExprVT = ExprType->getAsVectorType(); if (!ExprVT) { - unsigned InIdx = ExtVectorElementExpr::getAccessedFieldNo(0, EncFields); + unsigned InIdx = ExtVectorElementExpr::getAccessedFieldNo(0, Elts); llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); return RValue::get(Builder.CreateExtractElement(Vec, Elt, "tmp")); } @@ -202,7 +202,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV, if (NumResultElts == NumSourceElts) { llvm::SmallVector Mask; for (unsigned i = 0; i != NumResultElts; ++i) { - unsigned InIdx = ExtVectorElementExpr::getAccessedFieldNo(i, EncFields); + unsigned InIdx = ExtVectorElementExpr::getAccessedFieldNo(i, Elts); Mask.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx)); } @@ -218,7 +218,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV, // Extract/Insert each element of the result. for (unsigned i = 0; i != NumResultElts; ++i) { - unsigned InIdx = ExtVectorElementExpr::getAccessedFieldNo(i, EncFields); + unsigned InIdx = ExtVectorElementExpr::getAccessedFieldNo(i, Elts); llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); Elt = Builder.CreateExtractElement(Vec, Elt, "tmp"); @@ -312,7 +312,7 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, // value now. llvm::Value *Vec = Builder.CreateLoad(Dst.getExtVectorAddr(), "tmp"); // FIXME: Volatility. - unsigned EncFields = Dst.getExtVectorElts(); + const llvm::Constant *Elts = Dst.getExtVectorElts(); llvm::Value *SrcVal = Src.getScalarVal(); @@ -324,13 +324,13 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, i); Elt = Builder.CreateExtractElement(SrcVal, Elt, "tmp"); - unsigned Idx = ExtVectorElementExpr::getAccessedFieldNo(i, EncFields); + unsigned Idx = ExtVectorElementExpr::getAccessedFieldNo(i, Elts); llvm::Value *OutIdx = llvm::ConstantInt::get(llvm::Type::Int32Ty, Idx); Vec = Builder.CreateInsertElement(Vec, Elt, OutIdx, "tmp"); } } else { // If the Src is a scalar (not a vector) it must be updating one element. - unsigned InIdx = ExtVectorElementExpr::getAccessedFieldNo(0, EncFields); + unsigned InIdx = ExtVectorElementExpr::getAccessedFieldNo(0, Elts); llvm::Value *Elt = llvm::ConstantInt::get(llvm::Type::Int32Ty, InIdx); Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp"); } @@ -460,9 +460,28 @@ LValue CodeGenFunction:: EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { // Emit the base vector as an l-value. LValue Base = EmitLValue(E->getBase()); + + if (Base.isExtVectorElt()) { + llvm::Constant *BaseElts = Base.getExtVectorElts(); + llvm::Constant *ExprElts = E->getEncodedElementAccess(); + + llvm::SmallVector Indices; + + for (unsigned i = 0, e = E->getNumElements(); i != e; ++i) { + unsigned Idx = ExtVectorElementExpr::getAccessedFieldNo(i, ExprElts); + + if (isa(BaseElts)) + Indices.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0)); + else + Indices.push_back(cast(BaseElts->getOperand(Idx))); + } + llvm::Constant *NewElts = llvm::ConstantVector::get(&Indices[0], Indices.size()); + return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), NewElts); + } + assert(Base.isSimple() && "Can only subscript lvalue vectors here!"); - return LValue::MakeExtVectorElt(Base.getAddress(), + return LValue::MakeExtVectorElt(Base.getAddress(), E->getEncodedElementAccess()); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index a6caa379cc98..f067a0e2250b 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -161,8 +161,12 @@ class LValue { llvm::Value *V; union { - llvm::Value *VectorIdx; // Index into a vector subscript: V[i] - unsigned VectorElts; // Encoded ExtVector element subset: V.xyx + // Index into a vector subscript: V[i] + llvm::Value *VectorIdx; + + // ExtVector element subset: V.xyx + llvm::Constant *VectorElts; + struct { unsigned short StartBit; unsigned short Size; @@ -182,7 +186,7 @@ public: llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; } // extended vector elements. llvm::Value *getExtVectorAddr() const { assert(isExtVectorElt()); return V; } - unsigned getExtVectorElts() const { + llvm::Constant *getExtVectorElts() const { assert(isExtVectorElt()); return VectorElts; } @@ -216,11 +220,11 @@ public: return R; } - static LValue MakeExtVectorElt(llvm::Value *Vec, unsigned Elements) { + static LValue MakeExtVectorElt(llvm::Value *Vec, llvm::Constant *Elts) { LValue R; R.LVType = ExtVectorElt; R.V = Vec; - R.VectorElts = Elements; + R.VectorElts = Elts; return R; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4dcc68431845..5341ee7faa3f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -431,7 +431,8 @@ ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc, IndexExpr = RHSExp; // Component access limited to variables (reject vec4.rg[1]). - if (!isa(BaseExpr) && !isa(BaseExpr)) + if (!isa(BaseExpr) && !isa(BaseExpr) && + !isa(BaseExpr)) return Diag(LLoc, diag::err_ext_vector_component_access, SourceRange(LLoc, RLoc)); // FIXME: need to deal with const... @@ -461,6 +462,10 @@ QualType Sema:: CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, IdentifierInfo &CompName, SourceLocation CompLoc) { const ExtVectorType *vecType = baseType->getAsExtVectorType(); + + // This flag determines whether or not the component is to be treated as a + // special name, or a regular GLSL-style component access. + bool SpecialComponent = false; // The vector accessor can't exceed the number of elements. const char *compStr = CompName.getName(); @@ -469,8 +474,13 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, baseType.getAsString(), SourceRange(CompLoc)); return QualType(); } - // The component names must come from the same set. - if (vecType->getPointAccessorIdx(*compStr) != -1) { + + // Check that we've found one of the special components, or that the component + // names must come from the same set. + if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || + !strcmp(compStr, "e") || !strcmp(compStr, "o")) { + SpecialComponent = true; + } else if (vecType->getPointAccessorIdx(*compStr) != -1) { do compStr++; while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1); @@ -484,7 +494,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, while (*compStr && vecType->getTextureAccessorIdx(*compStr) != -1); } - if (*compStr) { + if (!SpecialComponent && *compStr) { // We didn't get to the end of the string. This means the component names // didn't come from the same set *or* we encountered an illegal name. Diag(OpLoc, diag::err_ext_vector_component_name_illegal, @@ -499,17 +509,27 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, else break; } - if (*compStr) { + if (!SpecialComponent && *compStr) { // We didn't get to the end of the string. This means a component accessor // exceeds the number of elements in the vector. Diag(OpLoc, diag::err_ext_vector_component_exceeds_length, baseType.getAsString(), SourceRange(CompLoc)); return QualType(); } + + // If we have a special component name, verify that the current vector length + // is an even number, since all special component names return exactly half + // the elements. + if (SpecialComponent && (vecType->getNumElements() & 1U)) { + return QualType(); + } + // The component accessor looks fine - now we need to compute the actual type. // The vector type is implied by the component accessor. For example, // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. - unsigned CompSize = strlen(CompName.getName()); + // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2. + unsigned CompSize = SpecialComponent ? vecType->getNumElements() / 2 + : strlen(CompName.getName()); if (CompSize == 1) return vecType->getElementType(); @@ -566,7 +586,8 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, MemberLoc, MemberType); } else if (BaseType->isExtVectorType() && OpKind == tok::period) { // Component access limited to variables (reject vec4.rg.g). - if (!isa(BaseExpr) && !isa(BaseExpr)) + if (!isa(BaseExpr) && !isa(BaseExpr) && + !isa(BaseExpr)) return Diag(OpLoc, diag::err_ext_vector_component_access, SourceRange(MemberLoc)); QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc); diff --git a/clang/test/Parser/ocu_vector_components.c b/clang/test/Parser/ocu_vector_components.c index 01e007b7442a..ec54631e7bbf 100644 --- a/clang/test/Parser/ocu_vector_components.c +++ b/clang/test/Parser/ocu_vector_components.c @@ -24,6 +24,5 @@ static void test() { vec2.xx = vec2_2.xy; // expected-error {{vector is not assignable (contains duplicate components)}} vec2.yx = vec2_2.xy; vec4 = (float4){ 1,2,3,4 }; - vec4.rg.g; // expected-error {{vector component access limited to variables}} - vec4.rg[1]; // expected-error {{vector component access limited to variables}} + vec4.rg.a; // expected-error {{vector component access exceeds type 'float2'}} }