[cfe-dev] Patch to add __builtin_shufflevector

Chris Lattner clattner at apple.com
Thu Feb 28 20:30:34 PST 2008


On Feb 28, 2008, at 6:52 PM, Eli Friedman wrote:

> 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?

This is very nice!  I have some minor stuff below, mostly little  
details.

+  ShuffleVectorExpr(Expr **args, unsigned nexpr,
+                    QualType Type, SourceLocation BLoc,
+                    SourceLocation RP) :
+    Expr(ShuffleVectorExprClass, Type), BuiltinLoc(BLoc),
+    RParenLoc(RP), SubExprs(args), NumExprs(nexpr) {}

This needs a comment that says that "args" must be new[]'d, and that  
ownership is transfered to the copy ctor.  Better yet, it would be  
good if the ctor actually did the new[] + memcpy itself, instead of  
having this behavior.

+  ~ShuffleVectorExpr() {
+    delete [] SubExprs;
+  }

This should delete the children ASTs as well as the array.


+  /// getExpr - Return the Expr at the specified index.
+  Expr *getExpr(unsigned Index) {
+    assert((Index < NumExprs) && "Arg access out of range!");
+    return SubExprs[Index];
+  }

This should probably also come in const form.  It would be nice to  
have an "int getShuffleMaskIdx(unsigned N)" method that converts the  
shuffle mask AST to a constant int and returns it, as a helper function.


--- Sema/SemaChecking.cpp	(revision 47702)
+++ Sema/SemaChecking.cpp	(working copy)
@@ -40,23 +40,36 @@
+    if (!CheckBuiltinCFStringArgument(TheCall->getArg(0))) {
+      delete TheCall;
+      return true;
+    }

SemaChecking should never delete the call on an error because  
ActOnCallExpr has an OwningPtr that will delete it if sema is not  
successful.  I think just removing the delete is ok from the error  
paths.  Actually, with this code in SemaExpr:

        if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRExpr- 
 >getDecl()))
-        if (CheckFunctionCall(FDecl, TheCall.get()))
-          return true;
+        return CheckFunctionCall(FDecl, TheCall.take());

the call will always be deleted.  I think this code should be:

        if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRExpr- 
 >getDecl())) {
+        ExprResult R = CheckFunctionCall(FDecl, TheCall.take());
          if (R.error) return;
          TheCall = R.Val;
        }

+/// 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) {

plz update the comment.

+  if (!Context.typesAreCompatible(
+          TheCall->getArg(0)->getType().getUnqualifiedType(),
+          TheCall->getArg(1)->getType().getUnqualifiedType())) {
+    return Diag(TheCall->getLocEnd(),  
diag::err_typecheck_call_too_few_args);
+  }

I think the (canonical) types should be required to be exactly  
identical, not just compatible, what do you think?

+    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);

These diags are good, but should be more descriptive.  Do you want to  
support -1 as undef?

I think that "Result >= llvm::APSInt(llvm::APInt(32, numElements*2)"  
will segfault if the index is something like 1LL.  Try something like:

   Result >= llvm::APSInt(llvm::APInt(Result.getBitWidth(),  
numElements*2))

oh except you also have to make the APSInt have the same sign as  
Result (try 1U as an index), and if it's signed, you want to reject  
things like -2.


+  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());

Instead of doing the new in Sema here, it would be nice if sema used a  
SmallvEctor<32>, and then had the ctor do the new/memcpy just to keep  
the ownership simple and clear.  I think the getLocStart() line is too  
long.

+  for (unsigned i = 2; i < E->getNumSubExprs(); i++) {
+    indices.push_back(cast<llvm::Constant>(CGF.EmitScalarExpr(E- 
 >getExpr(i))));
+  }

It would be nice to use a helper on ShuffleVectorExpr to get the index  
as an unsigned (evaluating as an i-c-e), instead of relying on  
EmitScalarExpr to do it.  Also, it would be nice to handle the undef  
case.


As a random thought, it would be relatively easy to make  
__builtin_shufflevector also support: __builtin_shufflevector(Vec,  
idx1, idx2, idx3, idx4) - a shuffle with a single vector (implicitly  
making the second vector be undef).  I think this would be handy, but  
is jsut syntactic sugar and may not be worth it.  What do you think?

Thanks for working on this!

-Chris










More information about the cfe-dev mailing list