@@ -4991,6 +4991,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
4991
4991
const Expr *SubExpr = E->getSubExpr ();
4992
4992
if (SubExpr->getType ()->isAnyComplexType ())
4993
4993
return this ->VisitComplexUnaryOperator (E);
4994
+ if (SubExpr->getType ()->isVectorType ())
4995
+ return this ->VisitVectorUnaryOperator (E);
4994
4996
std::optional<PrimType> T = classify (SubExpr->getType ());
4995
4997
4996
4998
switch (E->getOpcode ()) {
@@ -5312,6 +5314,110 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
5312
5314
return true ;
5313
5315
}
5314
5316
5317
+ template <class Emitter >
5318
+ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
5319
+ const Expr *SubExpr = E->getSubExpr ();
5320
+ assert (SubExpr->getType ()->isVectorType ());
5321
+
5322
+ if (DiscardResult)
5323
+ return this ->discard (SubExpr);
5324
+
5325
+ auto UnaryOp = E->getOpcode ();
5326
+ if (UnaryOp != UO_Plus && UnaryOp != UO_Minus && UnaryOp != UO_LNot &&
5327
+ UnaryOp != UO_Not)
5328
+ return this ->emitInvalid (E);
5329
+
5330
+ // Nothing to do here.
5331
+ if (UnaryOp == UO_Plus)
5332
+ return this ->delegate (SubExpr);
5333
+
5334
+ if (!Initializing) {
5335
+ std::optional<unsigned > LocalIndex = allocateLocal (SubExpr);
5336
+ if (!LocalIndex)
5337
+ return false ;
5338
+ if (!this ->emitGetPtrLocal (*LocalIndex, E))
5339
+ return false ;
5340
+ }
5341
+
5342
+ // The offset of the temporary, if we created one.
5343
+ unsigned SubExprOffset =
5344
+ this ->allocateLocalPrimitive (SubExpr, PT_Ptr, true , false );
5345
+ if (!this ->visit (SubExpr))
5346
+ return false ;
5347
+ if (!this ->emitSetLocal (PT_Ptr, SubExprOffset, E))
5348
+ return false ;
5349
+
5350
+ const auto *VecTy = SubExpr->getType ()->getAs <VectorType>();
5351
+ PrimType ElemT = classifyVectorElementType (SubExpr->getType ());
5352
+ auto getElem = [=](unsigned Offset, unsigned Index) -> bool {
5353
+ if (!this ->emitGetLocal (PT_Ptr, Offset, E))
5354
+ return false ;
5355
+ return this ->emitArrayElemPop (ElemT, Index, E);
5356
+ };
5357
+
5358
+ switch (UnaryOp) {
5359
+ case UO_Minus:
5360
+ for (unsigned I = 0 ; I != VecTy->getNumElements (); ++I) {
5361
+ if (!getElem (SubExprOffset, I))
5362
+ return false ;
5363
+ if (!this ->emitNeg (ElemT, E))
5364
+ return false ;
5365
+ if (!this ->emitInitElem (ElemT, I, E))
5366
+ return false ;
5367
+ }
5368
+ break ;
5369
+ case UO_LNot: { // !x
5370
+ // In C++, the logic operators !, &&, || are available for vectors. !v is
5371
+ // equivalent to v == 0.
5372
+ //
5373
+ // The result of the comparison is a vector of the same width and number of
5374
+ // elements as the comparison operands with a signed integral element type.
5375
+ //
5376
+ // https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
5377
+ QualType ResultVecTy = E->getType ();
5378
+ PrimType ResultVecElemT =
5379
+ classifyPrim (ResultVecTy->getAs <VectorType>()->getElementType ());
5380
+ for (unsigned I = 0 ; I != VecTy->getNumElements (); ++I) {
5381
+ if (!getElem (SubExprOffset, I))
5382
+ return false ;
5383
+ // operator ! on vectors returns -1 for 'truth', so negate it.
5384
+ if (!this ->emitPrimCast (ElemT, PT_Bool, Ctx.getASTContext ().BoolTy , E))
5385
+ return false ;
5386
+ if (!this ->emitInv (E))
5387
+ return false ;
5388
+ if (!this ->emitPrimCast (PT_Bool, ElemT, VecTy->getElementType (), E))
5389
+ return false ;
5390
+ if (!this ->emitNeg (ElemT, E))
5391
+ return false ;
5392
+ if (ElemT != ResultVecElemT &&
5393
+ !this ->emitPrimCast (ElemT, ResultVecElemT, ResultVecTy, E))
5394
+ return false ;
5395
+ if (!this ->emitInitElem (ResultVecElemT, I, E))
5396
+ return false ;
5397
+ }
5398
+ break ;
5399
+ }
5400
+ case UO_Not: // ~x
5401
+ for (unsigned I = 0 ; I != VecTy->getNumElements (); ++I) {
5402
+ if (!getElem (SubExprOffset, I))
5403
+ return false ;
5404
+ if (ElemT == PT_Bool) {
5405
+ if (!this ->emitInv (E))
5406
+ return false ;
5407
+ } else {
5408
+ if (!this ->emitComp (ElemT, E))
5409
+ return false ;
5410
+ }
5411
+ if (!this ->emitInitElem (ElemT, I, E))
5412
+ return false ;
5413
+ }
5414
+ break ;
5415
+ default :
5416
+ llvm_unreachable (" Unsupported unary operators should be handled up front" );
5417
+ }
5418
+ return true ;
5419
+ }
5420
+
5315
5421
template <class Emitter >
5316
5422
bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
5317
5423
if (DiscardResult)
0 commit comments