]> granicus.if.org Git - clang/commitdiff
Implement syntax/semantic analysis for OCU Vector Components.
authorSteve Naroff <snaroff@apple.com>
Fri, 27 Jul 2007 22:15:19 +0000 (22:15 +0000)
committerSteve Naroff <snaroff@apple.com>
Fri, 27 Jul 2007 22:15:19 +0000 (22:15 +0000)
Next step, AST support...

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40568 91177308-0d34-0410-b5e6-96231b3b80d8

Sema/Sema.h
Sema/SemaExpr.cpp
Sema/SemaStmt.cpp
include/clang/AST/Type.h
include/clang/Basic/DiagnosticKinds.def
test/Parser/ocu_vector_components.c [new file with mode: 0644]

index e1857b7583cabd3ee2bef71c43fd9999bd289d04..589161bfab8633923d5e79c9add36d81e5539cc5 100644 (file)
@@ -38,6 +38,7 @@ namespace clang {
   class ArrayType;
   class LabelStmt;
   class SwitchStmt;
+  class OCUVectorType;
   
 /// Sema - This implements semantic analysis and AST building for C.
 class Sema : public Action {
@@ -369,7 +370,11 @@ private:
   QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc);
   QualType CheckSizeOfAlignOfOperand(QualType type, SourceLocation loc, 
                                      bool isSizeof);
-    
+  
+  /// type checking primary expressions.
+  QualType CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc,
+                                   IdentifierInfo &Comp, SourceLocation CmpLoc);
+  
   /// C99: 6.7.5p3: Used by ParseDeclarator/ParseField to make sure we have
   /// a constant expression of type int with a value greater than zero.  If the
   /// array has an incomplete type or a valid constant size, return false,
index 00838f79c1b9cc73c1694c9cb67380c78dfd882e..91d6d8de9b19c5d6e6c4d68fddc5bd98ed6ed32d 100644 (file)
@@ -339,6 +339,57 @@ ParseArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
   return new ArraySubscriptExpr(LHSExp, RHSExp, ResultType, RLoc);
 }
 
+QualType Sema::
+CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc,
+                        IdentifierInfo &CompName, SourceLocation CompLoc) {
+  const OCUVectorType *vecType = baseType->isOCUVectorType();
+  
+  // The vector accessor can't exceed the number of elements.
+  const char *compStr = CompName.getName();
+  if (strlen(compStr) > vecType->getNumElements()) {
+    Diag(OpLoc, diag::err_ocuvector_component_exceeds_length, 
+                baseType.getAsString(), SourceRange(CompLoc));
+    return QualType();
+  }
+  // The component names must come from the same set.
+  if (vecType->isPointAccessor(*compStr))
+   do { compStr++; } while (*compStr && vecType->isPointAccessor(*compStr));
+  else if (vecType->isColorAccessor(*compStr))
+   do { compStr++; } while (*compStr && vecType->isColorAccessor(*compStr));
+  else if (vecType->isTextureAccessor(*compStr))
+   do { compStr++; } while (*compStr && vecType->isTextureAccessor(*compStr));
+    
+  if (*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_ocuvector_component_name_illegal, 
+         std::string(compStr,compStr+1), SourceRange(CompLoc));
+    return QualType();
+  }
+  // Each component accessor can't exceed the vector type.
+  compStr = CompName.getName();
+  while (*compStr) {
+    if (vecType->isAccessorWithinNumElements(*compStr))
+      compStr++;
+    else
+      break;
+  }
+  if (*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_ocuvector_component_exceeds_length, 
+                baseType.getAsString(), SourceRange(CompLoc));
+    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());
+  if (CompSize == 1)
+    return vecType->getElementType();
+  return Context.getOCUVectorType(vecType->getElementType(), CompSize);
+}
+
 Action::ExprResult Sema::
 ParseMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
                          tok::TokenKind OpKind, SourceLocation MemberLoc,
@@ -356,22 +407,27 @@ ParseMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
       return Diag(OpLoc, diag::err_typecheck_member_reference_arrow,
                   SourceRange(MemberLoc));
   }
-  // Get the member decl from the struct/union definition.
-  FieldDecl *MemberDecl;
+  // The base type is either a record or an OCUVectorType.
   if (const RecordType *RTy = BaseType->isRecordType()) {
     RecordDecl *RDecl = RTy->getDecl();
     if (RTy->isIncompleteType())
       return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RDecl->getName(),
                   BaseExpr->getSourceRange());
     // The record definition is complete, now make sure the member is valid.
-    if (!(MemberDecl = RDecl->getMember(&Member)))
+    FieldDecl *MemberDecl = RDecl->getMember(&Member);
+    if (!MemberDecl)
       return Diag(OpLoc, diag::err_typecheck_no_member, Member.getName(),
                   SourceRange(MemberLoc));
+    return new MemberExpr(BaseExpr, OpKind==tok::arrow, MemberDecl, MemberLoc);
+  } else if (BaseType->isOCUVectorType() && OpKind == tok::period) {
+    QualType ret = CheckOCUVectorComponent(BaseType, OpLoc, Member, MemberLoc);
+    if (ret.isNull())
+      return true;
+    // FIXME: instantiate a OCUVectorComponentExpr node...
+    return true;
   } else
     return Diag(OpLoc, diag::err_typecheck_member_reference_structUnion,
                 SourceRange(MemberLoc));
-  
-  return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl, MemberLoc);
 }
 
 /// ParseCallExpr - Handle a call to Fn with the specified array of arguments.
index f9e2c0a21a293490c221d5fb20ffe5b9127c3132..39e3b89919c96846a24f5caaad967cd4cd32ece7 100644 (file)
@@ -23,6 +23,7 @@ using namespace clang;
 
 Sema::StmtResult Sema::ParseExprStmt(ExprTy *expr) {
   Expr *E = static_cast<Expr*>(expr);
+  assert(E && "ParseExprStmt(): missing expression");
   
   // Exprs are statements, so there is no need to do a conversion here. However,
   // diagnose some potentially bad code.
index 17d2d0a3c0f6c56db0f612b43716b9e0da4ce0bb..3988b99966a47ba1220ca0c011ee994d3426adbd 100644 (file)
@@ -504,6 +504,28 @@ class OCUVectorType : public VectorType {
     VectorType(OCUVector, vecType, nElements, canonType) {} 
   friend class ASTContext;  // ASTContext creates these.
 public:
+  bool isPointAccessor(const char c) const {
+    return c == 'x' || c == 'y' || c == 'z' || c == 'w';
+  }
+  bool isColorAccessor(const char c) const {
+    return c == 'r' || c == 'g' || c == 'b' || c == 'a';
+  }
+  bool isTextureAccessor(const char c) const {
+    return c == 's' || c == 't' || c == 'p' || c == 'q';
+  };
+  bool isAccessorWithinNumElements(const char c) const {
+    switch (NumElements) {
+      default: assert(0 && "Illegal number of elements");
+      case 2: return c == 'x' || c == 'y' || 
+                     c == 'r' || c == 'g' ||
+                     c == 's' || c == 't';
+      case 3: return c == 'x' || c == 'y' || c == 'z' ||
+                     c == 'r' || c == 'g' || c == 'b' ||
+                     c == 's' || c == 't' || c == 'p';
+      case 4: return isPointAccessor(c) || isColorAccessor(c) || 
+                     isTextureAccessor(c);
+    }
+  }
   static bool classof(const Type *T) { 
     return T->getTypeClass() == Vector || T->getTypeClass() == OCUVector; 
   }
index 64de3aa16edf79766e76fabc77f01b3c382b8508..68e333a1e48bd6534a0e2f7c06cbe9f07f0a34ef 100644 (file)
@@ -445,6 +445,10 @@ DIAG(err_typecheck_vector_not_convertable, ERROR,
      "can't convert between vector values of different size ('%0' and '%1')")
 DIAG(err_typecheck_ocu_vector_not_typedef, ERROR,
      "ocu_vector_type only applies to types, not variables")
+DIAG(err_ocuvector_component_exceeds_length, ERROR,
+     "vector component access exceeds type '%0'")
+DIAG(err_ocuvector_component_name_illegal, ERROR,
+     "illegal vector component name '%0'")
 
 // Function Parameter Semantic Analysis.
 DIAG(err_param_with_void_type, ERROR,
diff --git a/test/Parser/ocu_vector_components.c b/test/Parser/ocu_vector_components.c
new file mode 100644 (file)
index 0000000..8c7aa98
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: clang -parse-ast-check %s
+
+typedef __attribute__(( ocu_vector_type(2) )) float float2;
+typedef __attribute__(( ocu_vector_type(3) )) float float3;
+typedef __attribute__(( ocu_vector_type(4) )) float float4;
+
+static void test() {
+    float2 vec2;
+    float3 vec3;
+    float4 vec4;
+    float f;
+
+    vec2.z; // // expected-error {{vector component access exceeds type 'float2'}}
+    vec2.rgba; // // expected-error {{vector component access exceeds type 'float2'}}
+    vec4.rgba;
+    vec4.rgbc; // // expected-error {{illegal vector component name 'c'}}
+    vec3 = vec4.rgb; // legal, shorten
+    f = vec2.x; // legal, shorten
+    vec4 = (float4){ 1,2,3,4 };
+}