Skip to content

Conversation

@ckoparkar
Copy link
Member

Fixes #153151.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" llvm:adt clang:bytecode Issues for the clang bytecode constexpr interpreter labels Aug 14, 2025
@ckoparkar
Copy link
Member Author

/cc @RKSimon @arsenm

@llvmbot
Copy link
Member

llvmbot commented Aug 14, 2025

@llvm/pr-subscribers-llvm-adt

@llvm/pr-subscribers-clang

Author: Chaitanya Koparkar (ckoparkar)

Changes

Fixes #153151.


Full diff: https://github.com/llvm/llvm-project/pull/153572.diff

6 Files Affected:

  • (modified) clang/include/clang/Basic/Builtins.td (+2-2)
  • (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+81)
  • (modified) clang/lib/AST/ExprConstShared.h (+4)
  • (modified) clang/lib/AST/ExprConstant.cpp (+77)
  • (modified) clang/test/Sema/constant-builtins-vector.cpp (+48)
  • (modified) llvm/include/llvm/ADT/APSInt.h (+6)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 84206cf8b368b..c5ad9a5d59dea 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1516,13 +1516,13 @@ def ElementwiseSubSat : Builtin {
 
 def ElementwiseFshl : Builtin {
   let Spellings = ["__builtin_elementwise_fshl"];
-  let Attributes = [NoThrow, Const, CustomTypeChecking];
+  let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
   let Prototype = "void(...)";
 }
 
 def ElementwiseFshr : Builtin {
   let Spellings = ["__builtin_elementwise_fshr"];
-  let Attributes = [NoThrow, Const, CustomTypeChecking];
+  let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
   let Prototype = "void(...)";
 }
 
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 307b77846969f..015f0443ede54 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2399,6 +2399,83 @@ static bool interp__builtin_elementwise_maxmin(InterpState &S, CodePtr OpPC,
   return true;
 }
 
+static bool interp__builtin_elementwise_fsh(InterpState &S, CodePtr OpPC,
+                                            const CallExpr *Call,
+                                            unsigned BuiltinID) {
+  assert(Call->getNumArgs() == 3);
+
+  const QualType Arg1Type = Call->getArg(0)->getType();
+  const QualType Arg2Type = Call->getArg(1)->getType();
+  const QualType Arg3Type = Call->getArg(2)->getType();
+
+  // Non-vector integer types.
+  if (!Arg1Type->isVectorType()) {
+    assert(!Arg2Type->isVectorType());
+    assert(!Arg3Type->isVectorType());
+
+    APSInt Shift = popToAPSInt(
+        S.Stk, *S.getContext().classify(Call->getArg(2)->getType()));
+    APSInt Lo = popToAPSInt(
+        S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
+    APSInt Hi = popToAPSInt(
+        S.Stk, *S.getContext().classify(Call->getArg(0)->getType()));
+    APSInt Result;
+    if (BuiltinID == Builtin::BI__builtin_elementwise_fshl) {
+      Result = HandleFshl(Hi, Lo, Shift);
+    } else if (BuiltinID == Builtin::BI__builtin_elementwise_fshr) {
+      Result = HandleFshr(Hi, Lo, Shift);
+    } else {
+      llvm_unreachable("Wrong builtin ID");
+    }
+    pushInteger(S, Result, Call->getType());
+    return true;
+  }
+
+  // Vector type.
+  assert(Arg1Type->isVectorType() &&
+         Arg2Type->isVectorType() &&
+         Arg3Type->isVectorType());
+
+  const VectorType *VecT = Arg1Type->castAs<VectorType>();
+  PrimType ElemT = *S.getContext().classify(VecT->getElementType());
+  unsigned NumElems = VecT->getNumElements();
+
+  assert(VecT->getElementType() ==
+         Arg2Type->castAs<VectorType>()->getElementType() &&
+         VecT->getElementType() ==
+         Arg3Type->castAs<VectorType>()->getElementType());
+  assert(NumElems == Arg2Type->castAs<VectorType>()->getNumElements() &&
+         NumElems == Arg3Type->castAs<VectorType>()->getNumElements());
+  assert(VecT->getElementType()->isIntegralOrEnumerationType());
+
+  const Pointer &VecShift = S.Stk.pop<Pointer>();
+  const Pointer &VecLo = S.Stk.pop<Pointer>();
+  const Pointer &VecHi = S.Stk.pop<Pointer>();
+  const Pointer &Dst = S.Stk.peek<Pointer>();
+  for (unsigned I = 0; I != NumElems; ++I) {
+      APSInt Hi;
+      APSInt Lo;
+      APSInt Shift;
+      INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+          Hi = VecHi.elem<T>(I).toAPSInt();
+          Lo = VecLo.elem<T>(I).toAPSInt();
+          Shift = VecShift.elem<T>(I).toAPSInt();
+        });
+      APSInt Result;
+      if (BuiltinID == Builtin::BI__builtin_elementwise_fshl) {
+        Result = HandleFshl(Hi, Lo, Shift);
+      } else if (BuiltinID == Builtin::BI__builtin_elementwise_fshr) {
+        Result = HandleFshr(Hi, Lo, Shift);
+      } else {
+        llvm_unreachable("Wrong builtin ID");
+      }
+      INT_TYPE_SWITCH_NO_BOOL(ElemT,
+                              { Dst.elem<T>(I) = static_cast<T>(Result); });
+  }
+  Dst.initializeAllElements();
+  return true;
+}
+
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
                       uint32_t BuiltinID) {
   if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
@@ -2810,6 +2887,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
   case Builtin::BI__builtin_elementwise_min:
     return interp__builtin_elementwise_maxmin(S, OpPC, Call, BuiltinID);
 
+  case Builtin::BI__builtin_elementwise_fshl:
+  case Builtin::BI__builtin_elementwise_fshr:
+    return interp__builtin_elementwise_fsh(S, OpPC, Call, BuiltinID);
+
   default:
     S.FFDiag(S.Current->getLocation(OpPC),
              diag::note_invalid_subexpr_in_const_expr)
diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h
index 401ae629c86bf..a1c5607ced700 100644
--- a/clang/lib/AST/ExprConstShared.h
+++ b/clang/lib/AST/ExprConstShared.h
@@ -18,6 +18,7 @@
 
 namespace llvm {
 class APFloat;
+class APSInt;
 }
 namespace clang {
 class QualType;
@@ -71,6 +72,9 @@ void HandleComplexComplexDiv(llvm::APFloat A, llvm::APFloat B, llvm::APFloat C,
                              llvm::APFloat D, llvm::APFloat &ResR,
                              llvm::APFloat &ResI);
 
+llvm::APSInt HandleFshl(llvm::APSInt Hi, llvm::APSInt Lo, llvm::APSInt Shift);
+llvm::APSInt HandleFshr(llvm::APSInt Hi, llvm::APSInt Lo, llvm::APSInt Shift);
+
 CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E,
                          UnaryExprOrTypeTrait ExprKind);
 
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 36dd0f5d7a065..083d84f7375fe 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -11723,6 +11723,39 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
 
     return Success(APValue(ResultElements.data(), ResultElements.size()), E);
   }
+  case Builtin::BI__builtin_elementwise_fshl:
+  case Builtin::BI__builtin_elementwise_fshr: {
+    APValue SourceHi, SourceLo, SourceShift;
+    if (!EvaluateAsRValue(Info, E->getArg(0), SourceHi) ||
+        !EvaluateAsRValue(Info, E->getArg(1), SourceLo) ||
+        !EvaluateAsRValue(Info, E->getArg(2), SourceShift))
+      return false;
+
+    QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
+
+    if (!DestEltTy->isIntegerType())
+      return false;
+
+    unsigned SourceLen = SourceHi.getVectorLength();
+    SmallVector<APValue> ResultElements;
+    ResultElements.reserve(SourceLen);
+
+    for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+      APSInt Hi = SourceHi.getVectorElt(EltNum).getInt();
+      APSInt Lo = SourceLo.getVectorElt(EltNum).getInt();
+      APSInt Shift = SourceShift.getVectorElt(EltNum).getInt();
+      switch (E->getBuiltinCallee()) {
+      case Builtin::BI__builtin_elementwise_fshl:
+        ResultElements.push_back(APValue(HandleFshl(Hi, Lo, Shift)));
+        break;
+      case Builtin::BI__builtin_elementwise_fshr:
+        ResultElements.push_back(APValue(HandleFshr(Hi, Lo, Shift)));
+        break;
+      }
+    }
+
+    return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+  }
   }
 }
 
@@ -13638,6 +13671,28 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
     APInt Result = std::min(LHS, RHS);
     return Success(APSInt(Result, !LHS.isSigned()), E);
   }
+  case Builtin::BI__builtin_elementwise_fshl:
+  case Builtin::BI__builtin_elementwise_fshr: {
+    if (!E->getArg(0)->isPRValue() ||
+        !E->getArg(1)->isPRValue() ||
+        !E->getArg(2)->isPRValue())
+      return false;
+    APSInt Hi, Lo, Shift;
+    if (!EvaluateInteger(E->getArg(0), Hi, Info) ||
+        !EvaluateInteger(E->getArg(1), Lo, Info) ||
+        !EvaluateInteger(E->getArg(2), Shift, Info))
+      return false;
+    switch (BuiltinOp) {
+    case Builtin::BI__builtin_elementwise_fshl: {
+      APSInt Result = HandleFshl(Hi, Lo, Shift);
+      return Success(Result, E);
+    }
+    case Builtin::BI__builtin_elementwise_fshr: {
+      APSInt Result = HandleFshr(Hi, Lo, Shift);
+      return Success(Result, E);
+    }
+    }
+  }
   case Builtin::BIstrlen:
   case Builtin::BIwcslen:
     // A call to strlen is not a constant expression.
@@ -16405,6 +16460,28 @@ void HandleComplexComplexDiv(APFloat A, APFloat B, APFloat C, APFloat D,
   }
 }
 
+// fshl(X,Y,Z): (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
+APSInt HandleFshl(APSInt Hi, APSInt Lo, APSInt Shift) {
+  bool IsUnsigned = Hi.isUnsigned();
+  APSInt BitWidth(llvm::APInt(Hi.getBitWidth(),
+                              static_cast<uint64_t>(Hi.getBitWidth())),
+                  IsUnsigned);
+  return APSInt((Hi << (Shift % BitWidth)) |
+                (Lo >> (BitWidth - (Shift % BitWidth))),
+                IsUnsigned);
+}
+
+// fshr(X,Y,Z): (X << (BW - (Z % BW))) | (Y >> (Z % BW))
+APSInt HandleFshr(APSInt Hi, APSInt Lo, APSInt Shift) {
+  bool IsUnsigned = Hi.isUnsigned();
+  APSInt BitWidth(llvm::APInt(Hi.getBitWidth(),
+                              static_cast<uint64_t>(Hi.getBitWidth())),
+                  IsUnsigned);
+  return APSInt((Hi << (BitWidth - (Shift % BitWidth))) |
+                (Lo >> (Shift % BitWidth)),
+                IsUnsigned);
+}
+
 bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
   if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
     return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
diff --git a/clang/test/Sema/constant-builtins-vector.cpp b/clang/test/Sema/constant-builtins-vector.cpp
index bc575dca98d77..c5f9c3956780e 100644
--- a/clang/test/Sema/constant-builtins-vector.cpp
+++ b/clang/test/Sema/constant-builtins-vector.cpp
@@ -876,3 +876,51 @@ static_assert(__builtin_elementwise_min(~0U, 0U) == 0U);
 static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4char){1, -2, 3, -4}, (vector4char){4, -3, 2, -1})) == (LITTLE_END ? 0xFC02FD01 : 0x01FD02FC));
 static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4uchar){1, 2, 3, 4}, (vector4uchar){4, 3, 2, 1})) == 0x01020201U);
 static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_min((vector4short){1, -2, 3, -4}, (vector4short){4, -3, 2, -1})) == (LITTLE_END ? 0xFFFC0002FFFD0001 : 0x0001FFFD0002FFFC));
+
+static_assert(__builtin_elementwise_fshl((unsigned char)255, (unsigned char)0, (unsigned char)8) == (unsigned char)255);
+static_assert(__builtin_elementwise_fshl((char)127, (char)0, (char)8) == (char)127);
+static_assert(__builtin_elementwise_fshl((unsigned char)0, (unsigned char)255, (unsigned char)8) == (unsigned char)0);
+static_assert(__builtin_elementwise_fshl((char)0, (char)127, (char)8) == (char)0);
+static_assert(__builtin_elementwise_fshr((unsigned char)255, (unsigned char)0, (unsigned char)8) == (unsigned char)0);
+static_assert(__builtin_elementwise_fshr((char)127, (char)0, (char)8) == (char)0);
+static_assert(__builtin_elementwise_fshr((unsigned char)0, (unsigned char)255, (unsigned char)8) == (unsigned char)255);
+static_assert(__builtin_elementwise_fshr((char)0, (char)127, (char)8) == (char)127);
+static_assert(__builtin_elementwise_fshl((unsigned int)4294967295, (unsigned int)0, (unsigned int)32) == (unsigned int)4294967295);
+static_assert(__builtin_elementwise_fshl((int)2147483647, (int)0, (int)32) == (int)2147483647);
+static_assert(__builtin_elementwise_fshl((unsigned int)0, (unsigned int)4294967295, (unsigned int)32) == (unsigned int)0);
+static_assert(__builtin_elementwise_fshl((int)0, (int)2147483647, (int)32) == (int)0);
+static_assert(__builtin_elementwise_fshr((unsigned int)4294967295, (unsigned int)0, (unsigned int)32) == (unsigned int)0);
+static_assert(__builtin_elementwise_fshr((int)2147483647, (int)0, (int)32) == (int)0);
+static_assert(__builtin_elementwise_fshr((unsigned int)0, (unsigned int)4294967295, (unsigned int)32) == (unsigned int)4294967295);
+static_assert(__builtin_elementwise_fshr((int)0, (int)2147483647, (int)32) == (int)2147483647);
+static_assert(__builtin_elementwise_fshl((unsigned long long)18446744073709551615ULL, (unsigned long long)0, (unsigned long long)64) == (unsigned long long)18446744073709551615ULL);
+static_assert(__builtin_elementwise_fshl((long long)9223372036854775807, (long long)0, (long long)64) == (long long)9223372036854775807);
+static_assert(__builtin_elementwise_fshl((unsigned long long)0, (unsigned long long)18446744073709551615ULL, (unsigned long long)64) == (unsigned long long)0);
+static_assert(__builtin_elementwise_fshl((long long)0, (long long)9223372036854775807, (long long)64) == (long long)0);
+static_assert(__builtin_elementwise_fshr((unsigned long long)18446744073709551615ULL, (unsigned long long)0, (unsigned long long)64) == (unsigned long long)0);
+static_assert(__builtin_elementwise_fshr((long long)9223372036854775807, (long long)0, (long long)64) == (long long)0);
+static_assert(__builtin_elementwise_fshr((unsigned long long)0, (unsigned long long)18446744073709551615ULL, (unsigned long long)64) == (unsigned long long)18446744073709551615ULL);
+static_assert(__builtin_elementwise_fshr((long long)0, (long long)9223372036854775807, (long long)64) == (long long)9223372036854775807);
+//
+static_assert(__builtin_elementwise_fshl((short) 1, (short) 2, (short) 3) == (short)8);
+static_assert(__builtin_elementwise_fshl((short) 2, (short) 1, (short) 3) == (short)16);
+static_assert(__builtin_elementwise_fshl(1, 2 , 2) == 4);
+static_assert(__builtin_elementwise_fshl(2L, 1L , 2L) == 8L);
+static_assert(__builtin_elementwise_fshr((unsigned char)1, (unsigned char)2, (unsigned char)3) == (unsigned char)32);
+//
+constexpr vector4uchar v4s_fshl_var =
+  __builtin_elementwise_fshl((vector4uchar){255, 15, 0, 2},
+                             (vector4uchar){0, 15, 255, 1},
+                             (vector4uchar){15, 11, 8, 3});
+static_assert(v4s_fshl_var[0] == 128);
+static_assert(v4s_fshl_var[1] == 120);
+static_assert(v4s_fshl_var[2] == 0);
+static_assert(v4s_fshl_var[3] == 16);
+constexpr vector4uchar v4s_fshr_var =
+  __builtin_elementwise_fshr((vector4uchar){255, 15, 0, 1},
+                             (vector4uchar){0, 15, 255, 2},
+                             (vector4uchar){15, 11, 8, 3});
+static_assert(v4s_fshr_var[0] == 254);
+static_assert(v4s_fshr_var[1] == 225);
+static_assert(v4s_fshr_var[2] == 255);
+static_assert(v4s_fshr_var[3] == 32);
diff --git a/llvm/include/llvm/ADT/APSInt.h b/llvm/include/llvm/ADT/APSInt.h
index 88a7a6e71c817..6112abed92100 100644
--- a/llvm/include/llvm/ADT/APSInt.h
+++ b/llvm/include/llvm/ADT/APSInt.h
@@ -152,6 +152,9 @@ class [[nodiscard]] APSInt : public APInt {
   APSInt operator>>(unsigned Amt) const {
     return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false);
   }
+  APSInt operator>>(const APSInt &Amt) const {
+    return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false);
+  }
   APSInt &operator>>=(unsigned Amt) {
     if (IsUnsigned)
       lshrInPlace(Amt);
@@ -211,6 +214,9 @@ class [[nodiscard]] APSInt : public APInt {
   APSInt operator<<(unsigned Bits) const {
     return APSInt(static_cast<const APInt &>(*this) << Bits, IsUnsigned);
   }
+  APSInt operator<<(const APSInt &Amt) const {
+    return APSInt(static_cast<const APInt &>(*this) << Amt, IsUnsigned);
+  }
   APSInt &operator<<=(unsigned Amt) {
     static_cast<APInt &>(*this) <<= Amt;
     return *this;

@RKSimon RKSimon requested review from RKSimon and el-ev August 14, 2025 12:54
Copy link
Member

@kuhar kuhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move the ADT changes to a separate PR and add unit tests?

@ckoparkar
Copy link
Member Author

Can you move the ADT changes to a separate PR and add unit tests?

@kuhar Will do. I'll wait for some reviews on the usage of that ADT change to be sure that it's actually going to be required for this and then create that separate PR.

@RKSimon
Copy link
Collaborator

RKSimon commented Aug 14, 2025

APIntOps fshl/r might be cleaner.

@ckoparkar
Copy link
Member Author

Sounds like the implementation of fshl/r looks OK. Let me create another PR for the ADT changes like kuhar suggested, I'll add the fshl/r functions there.

@ckoparkar
Copy link
Member Author

Working on updating this to use the new fshl/r APIntOps.

@github-actions
Copy link

github-actions bot commented Aug 22, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@ckoparkar
Copy link
Member Author

The other PRs this required have been merged, this is ready for review again.

@RKSimon RKSimon requested a review from tbaederr August 25, 2025 18:00
@ckoparkar ckoparkar marked this pull request as draft August 28, 2025 11:31
@RKSimon
Copy link
Collaborator

RKSimon commented Sep 3, 2025

@ckoparkar reverse-ping - what's still needed on this patch?

@ckoparkar
Copy link
Member Author

ckoparkar commented Sep 3, 2025

@RKSimon Not much is left after #155620. I need to clean up the type checking assertions in the new interpreter, probably just remove them. I'll finish it soon.

* main: (1483 commits)
  [clang] fix error recovery for invalid nested name specifiers (llvm#156772)
  Revert "[lldb] Add count for errors of DWO files in statistics and combine DWO file count functions" (llvm#156777)
  AMDGPU: Add agpr variants of multi-data DS instructions (llvm#156420)
  [libc][NFC] disable localtime on aarch64/baremetal (llvm#156776)
  [win/asan] Improve SharedReAlloc with HEAP_REALLOC_IN_PLACE_ONLY. (llvm#132558)
  [LLDB] Make internal shell the default for running LLDB lit tests. (llvm#156729)
  [lldb][debugserver] Max response size for qSpeedTest (llvm#156099)
  [AMDGPU] Define 1024 VGPRs on gfx1250 (llvm#156765)
  [flang] Check for BIND(C) name conflicts with alternate entries (llvm#156563)
  [RISCV] Add exhausted_gprs_fprs test to calling-conv-half.ll. NFC (llvm#156586)
  [NFC] Remove trailing whitespaces from `clang/include/clang/Basic/AttrDocs.td`
  [lldb] Mark scripted frames as synthetic instead of artificial (llvm#153117)
  [docs] Refine some of the wording in the quality developer policy (llvm#156555)
  [MLIR] Apply clang-tidy fixes for readability-identifier-naming in TransformOps.cpp (NFC)
  [MLIR] Add LDBG() tracing to VectorTransferOpTransforms.cpp (NFC)
  [NFC] Apply clang-format to PPCInstrFutureMMA.td (llvm#156749)
  [libc] implement template functions for localtime (llvm#110363)
  [llvm-objcopy][COFF] Update .symidx values after stripping (llvm#153322)
  Add documentation on debugging LLVM.
  [lldb] Add count for errors of DWO files in statistics and combine DWO file count functions (llvm#155023)
  ...
@ckoparkar ckoparkar marked this pull request as ready for review September 4, 2025 01:53
@ckoparkar ckoparkar requested a review from tbaederr September 4, 2025 01:53
Copy link
Collaborator

@RKSimon RKSimon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@RKSimon RKSimon merged commit 79ea319 into llvm:main Sep 4, 2025
12 checks passed
@ckoparkar ckoparkar deleted the ckoparkar/153151 branch September 4, 2025 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:bytecode Issues for the clang bytecode constexpr interpreter clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category llvm:adt

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Clang] Allow __builtin_elementwise_fshl/fshr builtin intrinsics to be used in constexpr

7 participants