]> granicus.if.org Git - clang/commitdiff
Implementation of __builtin_shufflevector, a portable builtin capable of
authorEli Friedman <eli.friedman@gmail.com>
Wed, 14 May 2008 19:38:39 +0000 (19:38 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Wed, 14 May 2008 19:38:39 +0000 (19:38 +0000)
expressing the full flexibility of the LLVM shufflevector instruction.
The expected immediate usage is in *mmintrin.h, so that they don't
depend on the mess of gcc-inherited (and not completely implemented)
shuffle builtins.

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

include/clang/AST/Builtins.def
include/clang/AST/Expr.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
lib/AST/Expr.cpp
lib/AST/StmtPrinter.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
test/CodeGen/builtinshufflevector.c [new file with mode: 0644]

index 33380baadb0ae983797a6e55e9830246615a0ce2..741b9d06c6a6f68c7b10353eb1f3e19b97bda5bb 100644 (file)
@@ -96,6 +96,8 @@ BUILTIN(__builtin_va_copy, "va&a", "n")
 BUILTIN(__builtin_memcpy, "v*v*vC*z", "n")
 BUILTIN(__builtin_expect, "iii"   , "nc")
 
+BUILTIN(__builtin_shufflevector, "v."   , "nc")
+
 BUILTIN(__builtin_alloca, "v*z"   , "n")
 
 // Atomic operators builtin.                                                  
index c4265989310246ca79a4c706faf015e8136fc2f4..6fb262732142fb0ee15a7add8aea13e07db61f68 100644 (file)
@@ -1095,6 +1095,75 @@ public:
   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), NumExprs(nexpr)
+  {
+    SubExprs = new Expr*[nexpr];
+    for (unsigned i = 0; i < nexpr; i++)
+      SubExprs[i] = args[i];
+  }
+    
+  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() {
+    for (unsigned i = 0; i < NumExprs; i++)
+      delete SubExprs[i];
+    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];
+  }
+  const Expr *getExpr(unsigned Index) const {
+    assert((Index < NumExprs) && "Arg access out of range!");
+    return SubExprs[Index];
+  }
+
+  int getShuffleMaskIdx(ASTContext &Ctx, unsigned N) {
+    llvm::APSInt Result(32);
+    bool result = getExpr(N+2)->isIntegerConstantExpr(Result, Ctx);
+    assert(result && "Must be integer constant");
+    return Result.getZExtValue();
+  }
+  
+  // 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 0df573b57bdb118e871bbf8716a8e43d2c06d03a..65ce33b4566eaf8ba5cb969badfceea07040e2ef 100644 (file)
@@ -103,8 +103,9 @@ STMT(75, ObjCIvarRefExpr      , Expr)
 
 // Clang Extensions.
 STMT(76, OverloadExpr         , Expr)
+STMT(77, ShuffleVectorExpr    , Expr)
 
-LAST_EXPR(76)
+LAST_EXPR(77)
 
 #undef STMT
 #undef FIRST_STMT
index 2063fb45228ba52bb5854e68566e45ea883a2080..dc215539381023ad7ef2508c993ab4e2067d6437 100644 (file)
@@ -1056,4 +1056,13 @@ DIAG(ext_return_missing_expr, EXTENSION,
 DIAG(ext_return_has_expr, EXTENSION,
      "void function '%0' should not return a value")
 
+DIAG(err_shufflevector_non_vector, ERROR,
+     "first two arguments to __builtin_shufflevector must be vectors")
+DIAG(err_shufflevector_incompatible_vector, ERROR,
+     "first two arguments to __builtin_shufflevector must have the same type")
+DIAG(err_shufflevector_nonconstant_argument, ERROR,
+     "indexes for __builtin_shufflevector must be constant integers")
+DIAG(err_shufflevector_argument_too_large, ERROR,
+     "indexes for __builtin_shufflevector must be less than the total number of vector elements")
+
 #undef DIAG
index 2ac30b4c8cb1e16eb3d9be937be8ae47d8c2785e..45c6a8721f84ccdc8905ab8dcb8abffa262b0260 100644 (file)
@@ -500,6 +500,7 @@ Expr *Expr::IgnoreParenCasts() {
 
 
 bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
+  return true;
   switch (getStmtClass()) {
   default:
     if (Loc) *Loc = getLocStart();
@@ -1363,6 +1364,14 @@ Stmt::child_iterator OverloadExpr::child_end() {
   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 bd6d0d44bf21c7a64b59b918e293a9cef3c1bdae..6e6594c0d8cc0efe9925cf97c0932436b5fa3d52 100644 (file)
@@ -755,6 +755,15 @@ void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) {
   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 4fb69d045e3ee452cad9bd571ab5c3c1800d9698..bdd7975fa0cadc8009d1a3e2a0e08429303b7094 100644 (file)
@@ -127,6 +127,7 @@ public:
   Value *VisitObjCMessageExpr(ObjCMessageExpr *E);
   Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { return EmitLoadOfLValue(E);}
   Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
+  Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
   Value *VisitMemberExpr(Expr *E)           { return EmitLoadOfLValue(E); }
   Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
   Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return EmitLoadOfLValue(E); }
@@ -449,6 +450,17 @@ Value *ScalarExprEmitter::VisitExpr(Expr *E) {
   return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
 }
 
+Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
+  llvm::SmallVector<llvm::Constant*, 32> 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.begin(), indices.size());
+  return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
+}
+
 Value *ScalarExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
   // Only the lookup mechanism and first two arguments of the method
   // implementation vary between runtimes.  We can get the receiver and
index e5aab61bb22a159b72ae1ce5c9eafeaf1ecbbb8c..9288e020fa725e3737e1acbb5f11420f87e14e2c 100644 (file)
@@ -887,10 +887,11 @@ private:
   //===--------------------------------------------------------------------===//
   // 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 6d3eea5e730b56365fbf5e95affc4f7e84547926..bbf43113ee74816be1559ba67112461b64ff9689 100644 (file)
@@ -30,7 +30,7 @@ using namespace clang;
 
 /// 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 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
   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 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
     CheckPrintfArguments(TheCall, HasVAListArg, format_idx);       
   }
   
-  return false;
+  return TheCall;
 }
 
 /// CheckBuiltinCFStringArgument - Checks that the argument to the builtin
@@ -200,6 +213,79 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
   return false;
 }
 
+/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector.
+// 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,
+                TheCall->getSourceRange());
+
+  QualType FAType = TheCall->getArg(0)->getType();
+  QualType SAType = TheCall->getArg(1)->getType();
+
+  if (!FAType->isVectorType() || !SAType->isVectorType()) {
+    Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector,
+         SourceRange(TheCall->getArg(0)->getLocStart(), 
+                     TheCall->getArg(1)->getLocEnd()));
+    delete TheCall;
+    return true;
+  }
+
+  if (TheCall->getArg(0)->getType().getCanonicalType().getUnqualifiedType() !=
+      TheCall->getArg(1)->getType().getCanonicalType().getUnqualifiedType()) {
+    Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector,
+         SourceRange(TheCall->getArg(0)->getLocStart(), 
+                     TheCall->getArg(1)->getLocEnd()));
+    delete TheCall;
+    return true;
+  }
+
+  unsigned numElements = FAType->getAsVectorType()->getNumElements();
+  if (TheCall->getNumArgs() != numElements+2) {
+    if (TheCall->getNumArgs() < numElements+2)
+      Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args,
+           TheCall->getSourceRange());
+    else
+      Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args,
+           TheCall->getSourceRange());
+    delete TheCall;
+    return true;
+  }
+
+  for (unsigned i = 2; i < TheCall->getNumArgs(); i++) {
+    llvm::APSInt Result(32);
+    if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context)) {
+      Diag(TheCall->getLocStart(),
+           diag::err_shufflevector_nonconstant_argument,
+           TheCall->getArg(i)->getSourceRange());
+      delete TheCall;
+      return true;
+    }
+    if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2) {
+      Diag(TheCall->getLocStart(),
+           diag::err_shufflevector_argument_too_large,
+           TheCall->getArg(i)->getSourceRange());
+      delete TheCall;
+      return true;
+    }
+  }
+
+  llvm::SmallVector<Expr*, 32> exprs;
+
+  for (unsigned i = 0; i < TheCall->getNumArgs(); i++) {
+    exprs.push_back(TheCall->getArg(i));
+    TheCall->setArg(i, 0);
+  }
+
+  ShuffleVectorExpr* E = new ShuffleVectorExpr(
+      exprs.begin(), 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 4567d82719fcc4b857bcf93bc00fe4c832a07c9a..64b53d588481a44dbee5b7021bba28050089c329 100644 (file)
@@ -723,8 +723,8 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
   }
 
   // Do special checking on direct calls to functions.
-  if (FDecl && CheckFunctionCall(FDecl, TheCall.get()))
-    return true;
+  if (FDecl)
+    return CheckFunctionCall(FDecl, TheCall.take());
 
   return TheCall.take();
 }
diff --git a/test/CodeGen/builtinshufflevector.c b/test/CodeGen/builtinshufflevector.c
new file mode 100644 (file)
index 0000000..46741d3
--- /dev/null
@@ -0,0 +1,5 @@
+// RUN: clang -emit-llvm < %s 2>&1 | grep 'shufflevector' | count 1
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a(v4si x, v4si y) {return __builtin_shufflevector(x, y, 3, 2, 5, 7);}
+