Per subject, patch to add __builtin_shufflevector.  This is needed to
implement mmintrin.h and friends efficiently on top of LLVM, because
LLVM isn't very smart about vectors, and vectors are hard(tm).  The
diagnostics aren't quite right, but other than that, does this patch
look okay?

-Eli
Index: include/clang/AST/Builtins.def
===================================================================
--- include/clang/AST/Builtins.def      (revision 47702)
+++ include/clang/AST/Builtins.def      (working copy)
@@ -96,6 +96,8 @@
 BUILTIN(__builtin_memcpy, "v*v*vC*z", "n")
 BUILTIN(__builtin_expect, "iii"   , "nc")
 
+BUILTIN(__builtin_shufflevector, "v."   , "nc")
+
 BUILTIN(__builtin_alloca, "v*z"   , "n")
 
 #undef BUILTIN
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h    (revision 47702)
+++ include/clang/AST/Expr.h    (working copy)
@@ -1099,6 +1099,57 @@
   virtual child_iterator child_end();
 };
 
+/// ShuffleVectorExpr - clang-specific builtin-in function
+/// __builtin_shufflevector.
+/// This AST node represents a operator that does a constant
+/// shuffle, similar to LLVM's shufflevector instruction. It takes
+/// two vectors and a variable number of constant indices,
+/// and returns the appropriately shuffled vector.
+class ShuffleVectorExpr : public Expr {
+  SourceLocation BuiltinLoc, RParenLoc;
+
+  // SubExprs - the list of values passed to the __builtin_shufflevector
+  // function. The first two are vectors, and the rest are constant
+  // indices.  The number of values in this list is always
+  // 2+the number of indices in the vector type.
+  Expr **SubExprs;
+  unsigned NumExprs;
+
+public:
+  ShuffleVectorExpr(Expr **args, unsigned nexpr,
+                    QualType Type, SourceLocation BLoc, 
+                    SourceLocation RP) : 
+    Expr(ShuffleVectorExprClass, Type), BuiltinLoc(BLoc),
+    RParenLoc(RP), SubExprs(args), NumExprs(nexpr) {}
+    
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(BuiltinLoc, RParenLoc);
+  }
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ShuffleVectorExprClass; 
+  }
+  static bool classof(const ShuffleVectorExpr *) { return true; }
+  
+  ~ShuffleVectorExpr() {
+    delete [] SubExprs;
+  }
+  
+  /// getNumSubExprs - Return the size of the SubExprs array.  This includes 
the
+  /// constant expression, the actual arguments passed in, and the function
+  /// pointers.
+  unsigned getNumSubExprs() const { return NumExprs; }
+  
+  /// getExpr - Return the Expr at the specified index.
+  Expr *getExpr(unsigned Index) {
+    assert((Index < NumExprs) && "Arg access out of range!");
+    return SubExprs[Index];
+  }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+};
+
 /// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
 /// This AST node is similar to the conditional operator (?:) in C, with 
 /// the following exceptions:
Index: include/clang/AST/StmtNodes.def
===================================================================
--- include/clang/AST/StmtNodes.def     (revision 47702)
+++ include/clang/AST/StmtNodes.def     (working copy)
@@ -102,8 +102,9 @@
 
 // Clang Extensions.
 STMT(76, OverloadExpr         , Expr)
+STMT(77, ShuffleVectorExpr    , Expr)
 
-LAST_EXPR(76)
+LAST_EXPR(77)
 
 #undef STMT
 #undef FIRST_STMT
Index: Sema/SemaChecking.cpp
===================================================================
--- Sema/SemaChecking.cpp       (revision 47702)
+++ Sema/SemaChecking.cpp       (working copy)
@@ -30,7 +30,7 @@
 
 /// CheckFunctionCall - Check a direct function call for various correctness
 /// and safety properties not strictly enforced by the C type system.
-bool
+Action::ExprResult
 Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
                         
   // Get the IdentifierInfo* for the called function.
@@ -40,23 +40,36 @@
   case Builtin::BI__builtin___CFStringMakeConstantString:
     assert(TheCall->getNumArgs() == 1 &&
            "Wrong # arguments to builtin CFStringMakeConstantString");
-    return CheckBuiltinCFStringArgument(TheCall->getArg(0));
+    if (!CheckBuiltinCFStringArgument(TheCall->getArg(0))) {
+      delete TheCall;
+      return true;
+    }
+    return TheCall;
   case Builtin::BI__builtin_va_start:
-    return SemaBuiltinVAStart(TheCall);
-    
+    if (!SemaBuiltinVAStart(TheCall)) {
+      delete TheCall;
+      return true;
+    }
+    return TheCall;
   case Builtin::BI__builtin_isgreater:
   case Builtin::BI__builtin_isgreaterequal:
   case Builtin::BI__builtin_isless:
   case Builtin::BI__builtin_islessequal:
   case Builtin::BI__builtin_islessgreater:
   case Builtin::BI__builtin_isunordered:
-    return SemaBuiltinUnorderedCompare(TheCall);
+    if (!SemaBuiltinUnorderedCompare(TheCall)) {
+      delete TheCall;
+      return true;
+    }
+    return TheCall;
+  case Builtin::BI__builtin_shufflevector:
+    return SemaBuiltinShuffleVector(TheCall);
   }
   
   // Search the KnownFunctionIDs for the identifier.
   unsigned i = 0, e = id_num_known_functions;
   for (; i != e; ++i) { if (KnownFunctionIDs[i] == FnInfo) break; }
-  if (i == e) return false;
+  if (i == e) return TheCall;
   
   // Printf checking.
   if (i <= id_vprintf) {
@@ -82,7 +95,7 @@
     CheckPrintfArguments(TheCall, HasVAListArg, format_idx);       
   }
   
-  return false;
+  return TheCall;
 }
 
 /// CheckBuiltinCFStringArgument - Checks that the argument to the builtin
@@ -200,7 +213,56 @@
   return false;
 }
 
+/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and
+/// friends.  This is declared to take (...), so we have to check everything.
+Action::ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
+  if (TheCall->getNumArgs() < 3)
+    return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args);
 
+  QualType FAType = TheCall->getArg(0)->getType();
+  QualType SAType = TheCall->getArg(1)->getType();
+  unsigned numElements;
+  if (const VectorType* VType = FAType->getAsVectorType()) {
+    numElements = VType->getNumElements();
+  } else if (const OCUVectorType* VType = FAType->getAsOCUVectorType()) {
+    numElements = VType->getNumElements();
+  } else {
+    return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args);
+  }
+
+  if (!Context.typesAreCompatible(
+          TheCall->getArg(0)->getType().getUnqualifiedType(),
+          TheCall->getArg(1)->getType().getUnqualifiedType())) {
+    return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args);
+  }
+
+  if (numElements+2 != TheCall->getNumArgs())
+    return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args);
+
+  for (unsigned i = 2; i < TheCall->getNumArgs(); i++) {
+    llvm::APSInt Result(32);
+    if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context))
+      return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args);
+    if (Result >= llvm::APSInt(llvm::APInt(32, numElements*2), false))
+      return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args);
+  }
+
+  Expr** exprs = new Expr*[TheCall->getNumArgs()];
+
+  for (unsigned i = 0; i < TheCall->getNumArgs(); i++) {
+    exprs[i] = TheCall->getArg(i);
+    TheCall->setArg(i, 0);
+  }
+
+  ShuffleVectorExpr* E = new ShuffleVectorExpr(exprs, numElements+2, FAType,
+                                               
TheCall->getCallee()->getLocStart(),
+                                               TheCall->getRParenLoc());
+
+  delete TheCall;
+  
+  return E;
+}
+
 /// CheckPrintfArguments - Check calls to printf (and similar functions) for
 /// correct use of format strings.  
 ///
Index: Sema/SemaExpr.cpp
===================================================================
--- Sema/SemaExpr.cpp   (revision 47702)
+++ Sema/SemaExpr.cpp   (working copy)
@@ -668,8 +668,7 @@
   if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
     if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr()))
       if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl()))
-        if (CheckFunctionCall(FDecl, TheCall.get()))
-          return true;
+        return CheckFunctionCall(FDecl, TheCall.take());
 
   return TheCall.take();
 }
Index: Sema/Sema.h
===================================================================
--- Sema/Sema.h (revision 47702)
+++ Sema/Sema.h (working copy)
@@ -796,10 +796,11 @@
   
//===--------------------------------------------------------------------===//
   // Extra semantic analysis beyond the C type system
 private:
-  bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
+  Action::ExprResult CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
   bool CheckBuiltinCFStringArgument(Expr* Arg);
   bool SemaBuiltinVAStart(CallExpr *TheCall);
   bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
+  Action::ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall);
   void CheckPrintfArguments(CallExpr *TheCall,
                             bool HasVAListArg, unsigned format_idx);
   void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
Index: AST/Expr.cpp
===================================================================
--- AST/Expr.cpp        (revision 47702)
+++ AST/Expr.cpp        (working copy)
@@ -1357,6 +1357,14 @@
   return reinterpret_cast<Stmt**>(&SubExprs[NumExprs]);
 }
 
+// ShuffleVectorExpr
+Stmt::child_iterator ShuffleVectorExpr::child_begin() {
+  return reinterpret_cast<Stmt**>(&SubExprs[0]);
+}
+Stmt::child_iterator ShuffleVectorExpr::child_end() {
+  return reinterpret_cast<Stmt**>(&SubExprs[NumExprs]);
+}
+
 // VAArgExpr
 Stmt::child_iterator VAArgExpr::child_begin() {
   return reinterpret_cast<Stmt**>(&Val);
Index: AST/StmtPrinter.cpp
===================================================================
--- AST/StmtPrinter.cpp (revision 47702)
+++ AST/StmtPrinter.cpp (working copy)
@@ -750,6 +750,15 @@
   OS << ")";
 }
 
+void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) {
+  OS << "__builtin_shufflevector(";
+  for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) {
+    if (i) OS << ", ";
+    PrintExpr(Node->getExpr(i));
+  }
+  OS << ")";
+}
+
 void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
   OS << "{ ";
   for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
Index: CodeGen/CGExprScalar.cpp
===================================================================
--- CodeGen/CGExprScalar.cpp    (revision 47702)
+++ CodeGen/CGExprScalar.cpp    (working copy)
@@ -121,6 +121,7 @@
     return EmitLoadOfLValue(E);
   }
   Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+  Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
   Value *VisitMemberExpr(Expr *E)           { return EmitLoadOfLValue(E); }
   Value *VisitOCUVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
   Value *VisitStringLiteral(Expr *E)  { return EmitLValue(E).getAddress(); }
@@ -443,6 +444,17 @@
   return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
 }
 
+Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+  std::vector<llvm::Constant*> indices;
+  for (unsigned i = 2; i < E->getNumSubExprs(); i++) {
+    indices.push_back(cast<llvm::Constant>(CGF.EmitScalarExpr(E->getExpr(i))));
+  }
+  Value* V1 = CGF.EmitScalarExpr(E->getExpr(0));
+  Value* V2 = CGF.EmitScalarExpr(E->getExpr(1));
+  Value* SV = llvm::ConstantVector::get(indices);
+  return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
+}
+
 Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
   // Emit subscript expressions in rvalue context's.  For most cases, this just
   // loads the lvalue formed by the subscript expr.  However, we have to be
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev

Reply via email to