[clang] [clang] Introduce __builtin_splatvector (PR #212758)

Paul Osmialowski via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 29 05:39:56 PDT 2026


https://github.com/pawosm-arm created https://github.com/llvm/llvm-project/pull/212758

The aim of this patch is to introduce a new builtin for doing a vector splat which could work with both fided-size and scalable vectors (regardless of the underlying architecture) and also could be used in the C++ templates.

Most of the code (including the tests) follows similar code of __builtin_convertvector.

The new builtin takes two parameters: a scalar value and a desired vector type (fixed-size or scalable). A type conversion is attempted when the type of the value is not the same as the element type of the requested vector type.

>From 22b1add31ecd0ef18c2ccc75c1021fcf391126af Mon Sep 17 00:00:00 2001
From: Paul Osmialowski <pawel.osmialowski at arm.com>
Date: Sat, 25 Jul 2026 09:19:51 +0000
Subject: [PATCH] [clang] Introduce __builtin_splatvector

The aim of this patch is to introduce a new builtin for doing a vector
splat which could work with both fided-size and scalable vectors
(regardless of the underlying architecture) and also could be used in
the C++ templates.

Most of the code (including the tests) follows similar code of
__builtin_convertvector.

The new builtin takes two parameters: a scalar value and a desired
vector type (fixed-size or scalable). A type conversion is attempted
when the type of the value is not the same as the element type of the
requested vector type.
---
 clang/docs/LanguageExtensions.md              |  45 +-
 clang/docs/LibASTMatchersReference.html       |   5 +
 clang/include/clang/AST/ComputeDependence.h   |   2 +
 clang/include/clang/AST/Expr.h                | 126 +++++
 clang/include/clang/AST/RecursiveASTVisitor.h |   1 +
 clang/include/clang/AST/Stmt.h                |  15 +
 clang/include/clang/AST/TextNodeDumper.h      |   1 +
 clang/include/clang/ASTMatchers/ASTMatchers.h |   4 +
 clang/include/clang/Basic/Builtins.td         |   6 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/include/clang/Basic/StmtNodes.td        |   1 +
 clang/include/clang/Basic/TokenKinds.def      |   1 +
 clang/include/clang/Sema/Sema.h               |  14 +
 .../include/clang/Serialization/ASTBitCodes.h |   3 +
 clang/lib/AST/ASTImporter.cpp                 |  17 +
 clang/lib/AST/ComputeDependence.cpp           |   9 +
 clang/lib/AST/Expr.cpp                        |  21 +
 clang/lib/AST/ExprClassification.cpp          |   1 +
 clang/lib/AST/ExprConstant.cpp                |   1 +
 clang/lib/AST/ItaniumMangle.cpp               |   1 +
 clang/lib/AST/StmtPrinter.cpp                 |   8 +
 clang/lib/AST/StmtProfile.cpp                 |   4 +
 clang/lib/AST/TextNodeDumper.cpp              |   6 +
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp |   2 +
 clang/lib/ASTMatchers/Dynamic/Registry.cpp    |   1 +
 clang/lib/CodeGen/CGExprScalar.cpp            |  87 +++
 clang/lib/Parse/ParseExpr.cpp                 |  30 +
 clang/lib/Sema/SemaChecking.cpp               |  22 +
 clang/lib/Sema/SemaExceptionSpec.cpp          |   1 +
 clang/lib/Sema/SemaExpr.cpp                   |   8 +
 clang/lib/Sema/TreeTransform.h                |  28 +
 clang/lib/Serialization/ASTReaderStmt.cpp     |  21 +
 clang/lib/Serialization/ASTWriterStmt.cpp     |  13 +
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |   1 +
 clang/test/AST/ast-dump-fpfeatures.cpp        |  19 +
 clang/test/CodeGen/pragma-fenv_access.c       |  40 ++
 .../CodeGen/splatvector-sizeless-aarch64.c    | 518 +++++++++++++++++
 .../test/CodeGen/splatvector-sizeless-riscv.c | 518 +++++++++++++++++
 clang/test/CodeGen/splatvector-template.cpp   |  17 +
 clang/test/CodeGen/splatvector.c              | 524 ++++++++++++++++++
 clang/test/PCH/exprs.h                        |   4 +
 clang/test/Preprocessor/feature_tests.c       |   1 +
 clang/test/Preprocessor/feature_tests.cpp     |   5 +
 clang/test/Sema/splatvector.c                 |  16 +
 clang/test/Sema/vector-bool-assign.c          |   6 +
 clang/test/Sema/vector-bool-assign.cpp        |   6 +
 clang/tools/libclang/CXCursor.cpp             |   1 +
 clang/unittests/AST/ASTImporterTest.cpp       |  22 +
 .../ASTMatchers/ASTMatchersNodeTest.cpp       |  10 +
 49 files changed, 2215 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGen/splatvector-sizeless-aarch64.c
 create mode 100644 clang/test/CodeGen/splatvector-sizeless-riscv.c
 create mode 100644 clang/test/CodeGen/splatvector-template.cpp
 create mode 100644 clang/test/CodeGen/splatvector.c
 create mode 100644 clang/test/Sema/splatvector.c

diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md
index f5313e0378ca0..af38f05259bcd 100644
--- a/clang/docs/LanguageExtensions.md
+++ b/clang/docs/LanguageExtensions.md
@@ -690,7 +690,7 @@ these attributes requires the command line option `-msve-vector-bits=<N>` or
 supported on both sizeless and VLS types. For RVV, the operators are only
 supported on VLS types.
 
-See also {ref}`langext-builtin-shufflevector`, {ref}`langext-builtin-convertvector`.
+See also {ref}`langext-builtin-shufflevector`, {ref}`langext-builtin-splatvector` ,{ref}`langext-builtin-convertvector`.
 
 <aside class="footnote-list brackets">
 <aside class="footnote brackets" id="id5" role="doc-footnote">
@@ -3563,6 +3563,49 @@ indices specified.
 
 Query for this feature with `__has_builtin(__builtin_shufflevector)`.
 
+(langext-__builtin_splatvector)=
+(langext-builtin-splatvector)=
+
+### `__builtin_splatvector`
+
+`__builtin_splatvector` is used to express generic vector splat
+operations. This builtin can be used within constant expressions.
+
+**Syntax**:
+
+```c++
+__builtin_splatvector(src_value, dst_vec_type)
+```
+
+**Examples**:
+
+```c++
+typedef double vector4double __attribute__((__vector_size__(32)));
+typedef float  vector4float  __attribute__((__vector_size__(16)));
+typedef short  vector4short  __attribute__((__vector_size__(8)));
+float f; short s;
+
+// splat a float value to a vector of 4 doubles.
+__builtin_splatvector(f, vector4double)
+// equivalent to:
+(vector4double) { (double) f, (double) f, (double) f, (double) f }
+
+// splat a short integer value to a vector of 4 floats.
+__builtin_splatvector(s, vector4float)
+// equivalent to:
+(vector4float) { (float) s, (float) s, (float) s, (float) s }
+```
+
+**Description**:
+
+The first argument to `__builtin_splatvector` is a value, and the second
+argument is a vector type.
+
+The result of `__builtin_splatvector` is a vector with the value from the
+first argument copied to each its element.
+
+Query for this feature with `__has_builtin(__builtin_splatvector)`.
+
 (langext-__builtin_convertvector)=
 (langext-builtin-convertvector)=
 
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 7e0bbbcb18938..035662a4976c0 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -2347,6 +2347,11 @@ <h2 id="decl-matchers">Node Matchers</h2>
 </pre></td></tr>
 
 
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('splatVectorExpr0')"><a name="splatVectorExpr0Anchor">splatVectorExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1SplatVectorExpr.html">SplatVectorExpr</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="splatVectorExpr0"><pre>Matches builtin function __builtin_splatvector.
+</pre></td></tr>
+
+
 <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('stmt0')"><a name="stmt0Anchor">stmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>...</td></tr>
 <tr><td colspan="4" class="doc" id="stmt0"><pre>Matches statements.
 
diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h
index 3a3c86842501a..f70aaeb06c89a 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -37,6 +37,7 @@ class BinaryOperator;
 class ConditionalOperator;
 class BinaryConditionalOperator;
 class StmtExpr;
+class SplatVectorExpr;
 class ConvertVectorExpr;
 class VAArgExpr;
 class ChooseExpr;
@@ -128,6 +129,7 @@ ExprDependence computeDependence(BinaryOperator *E);
 ExprDependence computeDependence(ConditionalOperator *E);
 ExprDependence computeDependence(BinaryConditionalOperator *E);
 ExprDependence computeDependence(StmtExpr *E, unsigned TemplateDepth);
+ExprDependence computeDependence(SplatVectorExpr *E);
 ExprDependence computeDependence(ConvertVectorExpr *E);
 ExprDependence computeDependence(VAArgExpr *E);
 ExprDependence computeDependence(ChooseExpr *E);
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index f95f87cc4e8e0..669247d158ae1 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -4717,6 +4717,132 @@ class ShuffleVectorExpr : public Expr {
   }
 };
 
+/// SplatVectorExpr - clang-specific builtin-in function
+/// __builtin_splatvector.
+/// This AST node represents a operator that does a splat,
+/// similar to LLVM's splat instruction. It takes a scalar value
+/// and returns the appropriately splatted vector.
+class SplatVectorExpr final
+    : public Expr,
+      private llvm::TrailingObjects<SplatVectorExpr, FPOptionsOverride> {
+private:
+  Stmt *SrcExpr;
+  TypeSourceInfo *TInfo;
+  SourceLocation BuiltinLoc, RParenLoc;
+
+  friend TrailingObjects;
+  friend class ASTReader;
+  friend class ASTStmtReader;
+  explicit SplatVectorExpr(bool HasFPFeatures, EmptyShell Empty)
+      : Expr(SplatVectorExprClass, Empty) {
+    SplatVectorExprBits.HasFPFeatures = HasFPFeatures;
+  }
+
+  SplatVectorExpr(Expr *SrcExpr, TypeSourceInfo *TI, QualType DstType,
+                  ExprValueKind VK, ExprObjectKind OK,
+                  SourceLocation BuiltinLoc, SourceLocation RParenLoc,
+                  FPOptionsOverride FPFeatures)
+      : Expr(SplatVectorExprClass, DstType, VK, OK), SrcExpr(SrcExpr),
+        TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {
+    SplatVectorExprBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
+    if (hasStoredFPFeatures())
+      setStoredFPFeatures(FPFeatures);
+    setDependence(computeDependence(this));
+  }
+
+  size_t numTrailingObjects(OverloadToken<FPOptionsOverride>) const {
+    return SplatVectorExprBits.HasFPFeatures ? 1 : 0;
+  }
+
+  FPOptionsOverride &getTrailingFPFeatures() {
+    assert(SplatVectorExprBits.HasFPFeatures);
+    return *getTrailingObjects();
+  }
+
+  const FPOptionsOverride &getTrailingFPFeatures() const {
+    assert(SplatVectorExprBits.HasFPFeatures);
+    return *getTrailingObjects();
+  }
+
+public:
+  static SplatVectorExpr *CreateEmpty(const ASTContext &C, bool hasFPFeatures);
+
+  static SplatVectorExpr *Create(const ASTContext &C, Expr *SrcExpr,
+                                 TypeSourceInfo *TI, QualType DstType,
+                                 ExprValueKind VK, ExprObjectKind OK,
+                                 SourceLocation BuiltinLoc,
+                                 SourceLocation RParenLoc,
+                                 FPOptionsOverride FPFeatures);
+
+  /// Get the FP contractibility status of this operator. Only meaningful for
+  /// operations on floating point types.
+  bool isFPContractableWithinStatement(const LangOptions &LO) const {
+    return getFPFeaturesInEffect(LO).allowFPContractWithinStatement();
+  }
+
+  /// Is FPFeatures in Trailing Storage?
+  bool hasStoredFPFeatures() const {
+    return SplatVectorExprBits.HasFPFeatures;
+  }
+
+  /// Get FPFeatures from trailing storage.
+  FPOptionsOverride getStoredFPFeatures() const {
+    return getTrailingFPFeatures();
+  }
+
+  /// Get the store FPOptionsOverride or default if not stored.
+  FPOptionsOverride getStoredFPFeaturesOrDefault() const {
+    return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
+  }
+
+  /// Set FPFeatures in trailing storage, used by Serialization & ASTImporter.
+  void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; }
+
+  /// Get the FP features status of this operator. Only meaningful for
+  /// operations on floating point types.
+  FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
+    if (SplatVectorExprBits.HasFPFeatures)
+      return getStoredFPFeatures().applyOverrides(LO);
+    return FPOptions::defaultWithoutTrailingStorage(LO);
+  }
+
+  FPOptionsOverride getFPOptionsOverride() const {
+    if (SplatVectorExprBits.HasFPFeatures)
+      return getStoredFPFeatures();
+    return FPOptionsOverride();
+  }
+
+  /// getSrcExpr - Return the Expr to be splat.
+  Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); }
+
+  /// getTypeSourceInfo - Return the destination type.
+  TypeSourceInfo *getTypeSourceInfo() const {
+    return TInfo;
+  }
+  void setTypeSourceInfo(TypeSourceInfo *ti) {
+    TInfo = ti;
+  }
+
+  /// getBuiltinLoc - Return the location of the __builtin_splatvector token.
+  SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+
+  /// getRParenLoc - Return the location of final right parenthesis.
+  SourceLocation getRParenLoc() const { return RParenLoc; }
+
+  SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; }
+  SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == SplatVectorExprClass;
+  }
+
+  // Iterators
+  child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
+  const_child_range children() const {
+    return const_child_range(&SrcExpr, &SrcExpr + 1);
+  }
+};
+
 /// ConvertVectorExpr - Clang builtin function __builtin_convertvector
 /// This AST node provides support for converting a vector type to another
 /// vector type of the same arity.
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index cdf8a71d54cc9..782eb04e7f993 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3050,6 +3050,7 @@ DEF_TRAVERSE_STMT(UnresolvedSYCLKernelCallStmt, {
 DEF_TRAVERSE_STMT(OpenACCAsteriskSizeExpr, {})
 DEF_TRAVERSE_STMT(PredefinedExpr, {})
 DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
+DEF_TRAVERSE_STMT(SplatVectorExpr, {})
 DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
 DEF_TRAVERSE_STMT(StmtExpr, {})
 DEF_TRAVERSE_STMT(SourceLocExpr, {})
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 69db8252f931e..e58189fa60194 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1315,6 +1315,20 @@ class alignas(void *) Stmt {
     SourceLocation Loc;
   };
 
+  class SplatVectorExprBitfields {
+    friend class SplatVectorExpr;
+
+    LLVM_PREFERRED_TYPE(ExprBitfields)
+    unsigned : NumExprBits;
+
+    //
+    /// This is only meaningful for operations on floating point
+    /// types when additional values need to be in trailing storage.
+    /// It is 0 otherwise.
+    LLVM_PREFERRED_TYPE(bool)
+    unsigned HasFPFeatures : 1;
+  };
+
   class ConvertVectorExprBitfields {
     friend class ConvertVectorExpr;
 
@@ -1414,6 +1428,7 @@ class alignas(void *) Stmt {
 
     // Clang Extensions
     OpaqueValueExprBitfields OpaqueValueExprBits;
+    SplatVectorExprBitfields SplatVectorExprBits;
     ConvertVectorExprBitfields ConvertVectorExprBits;
   };
 
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index 41ddd88a8326c..9d3e9f3da14e4 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -438,6 +438,7 @@ class TextNodeDumper
   void VisitOpenACCRoutineDeclAttr(const OpenACCRoutineDeclAttr *A);
   void VisitEmbedExpr(const EmbedExpr *S);
   void VisitAtomicExpr(const AtomicExpr *AE);
+  void VisitSplatVectorExpr(const SplatVectorExpr *S);
   void VisitConvertVectorExpr(const ConvertVectorExpr *S);
 };
 
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 02d52b51a45c9..0d0310f7e987c 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2653,6 +2653,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr>
 extern const internal::VariadicDynCastAllOfMatcher<Stmt, ChooseExpr>
     chooseExpr;
 
+/// Matches builtin function __builtin_splatvector.
+extern const internal::VariadicDynCastAllOfMatcher<Stmt, SplatVectorExpr>
+    splatVectorExpr;
+
 /// Matches builtin function __builtin_convertvector.
 extern const internal::VariadicDynCastAllOfMatcher<Stmt, ConvertVectorExpr>
     convertVectorExpr;
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 06d559a5c3ce2..811d21dbff0a3 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1475,6 +1475,12 @@ def ShuffleVector : Builtin {
   let Prototype = "void(...)";
 }
 
+def SplatVector : Builtin {
+  let Spellings = ["__builtin_splatvector"];
+  let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
+  let Prototype = "void(...)";
+}
+
 def ConvertVector : Builtin {
   let Spellings = ["__builtin_convertvector"];
   let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d9d0d485f16ac..4d495196ced25 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11482,6 +11482,9 @@ def err_shufflevector_argument_too_large : Error<
 def err_shufflevector_minus_one_is_undefined_behavior_constexpr : Error<
   "index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position %0 is not permitted in a constexpr context">;
 
+def err_splatvector_non_scalar : Error<
+  "first argument to __builtin_splatvector must be a single value">;
+
 def err_convertvector_non_vector : Error<
   "first argument to __builtin_convertvector must be a vector">;
 def err_convertvector_constexpr_unsupported_vector_cast : Error<
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index f5fa397c92ef3..9b43de13060d1 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -218,6 +218,7 @@ def CUDAKernelCallExpr : StmtNode<CallExpr>;
 
 // Clang Extensions.
 def ShuffleVectorExpr : StmtNode<Expr>;
+def SplatVectorExpr : StmtNode<Expr>;
 def ConvertVectorExpr : StmtNode<Expr>;
 def BlockExpr : StmtNode<Expr>;
 def OpaqueValueExpr : StmtNode<Expr>;
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 3d8d42caa39cf..ad3e2235909ad 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -668,6 +668,7 @@ ALIAS("_w64"             , __w64        , KEYMSCOMPAT)
 ALIAS("_pascal"      , __pascal   , KEYBORLAND)
 
 // Clang Extensions.
+KEYWORD(__builtin_splatvector            , KEYALL)
 KEYWORD(__builtin_convertvector          , KEYALL)
 ALIAS("__char16_t"   , char16_t          , KEYCXX)
 ALIAS("__char32_t"   , char32_t          , KEYCXX)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 778c1a2f5c427..661d6e282a33e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2680,6 +2680,11 @@ class Sema final : public SemaBase {
   // Used by C++ template instantiation.
   ExprResult BuiltinShuffleVector(CallExpr *TheCall);
 
+  /// SplatVectorExpr - Handle __builtin_splatvector
+  ExprResult SplatVectorExpr(Expr *E, TypeSourceInfo *TInfo,
+                             SourceLocation BuiltinLoc,
+                             SourceLocation RParenLoc);
+
   /// ConvertVectorExpr - Handle __builtin_convertvector
   ExprResult ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
                                SourceLocation BuiltinLoc,
@@ -7720,6 +7725,15 @@ class Sema final : public SemaBase {
 
   //===---------------------------- Clang Extensions ----------------------===//
 
+  /// ActOnSplatVectorExpr - create a new splat-vector expression from the
+  /// provided argument.
+  ///
+  /// __builtin_splatvector( value, dst type )
+  ///
+  ExprResult ActOnSplatVectorExpr(Expr *E, ParsedType ParsedDestTy,
+                                  SourceLocation BuiltinLoc,
+                                  SourceLocation RParenLoc);
+
   /// ActOnConvertVectorExpr - create a new convert-vector expression from the
   /// provided arguments.
   ///
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 671341488278e..c99aff4a6c61e 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1756,6 +1756,9 @@ enum StmtCode {
   /// A ShuffleVectorExpr record.
   EXPR_SHUFFLE_VECTOR,
 
+  /// A SplatVectorExpr record.
+  EXPR_SPLAT_VECTOR,
+
   /// A ConvertVectorExpr record.
   EXPR_CONVERT_VECTOR,
 
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 3ad71a223903c..9c28fdb3a77fe 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -628,6 +628,7 @@ namespace clang {
     ExpectedStmt VisitSourceLocExpr(SourceLocExpr *E);
     ExpectedStmt VisitVAArgExpr(VAArgExpr *E);
     ExpectedStmt VisitChooseExpr(ChooseExpr *E);
+    ExpectedStmt VisitSplatVectorExpr(SplatVectorExpr *E);
     ExpectedStmt VisitConvertVectorExpr(ConvertVectorExpr *E);
     ExpectedStmt VisitShuffleVectorExpr(ShuffleVectorExpr *E);
     ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E);
@@ -7804,6 +7805,22 @@ ExpectedStmt ASTNodeImporter::VisitChooseExpr(ChooseExpr *E) {
                  ToRParenLoc, CondIsTrue);
 }
 
+ExpectedStmt ASTNodeImporter::VisitSplatVectorExpr(SplatVectorExpr *E) {
+  Error Err = Error::success();
+  auto *ToSrcExpr = importChecked(Err, E->getSrcExpr());
+  auto ToRParenLoc = importChecked(Err, E->getRParenLoc());
+  auto ToBuiltinLoc = importChecked(Err, E->getBuiltinLoc());
+  auto ToType = importChecked(Err, E->getType());
+  auto *ToTSI = importChecked(Err, E->getTypeSourceInfo());
+  if (Err)
+    return std::move(Err);
+
+  return SplatVectorExpr::Create(
+      Importer.getToContext(), ToSrcExpr, ToTSI, ToType, E->getValueKind(),
+      E->getObjectKind(), ToBuiltinLoc, ToRParenLoc,
+      E->getStoredFPFeaturesOrDefault());
+}
+
 ExpectedStmt ASTNodeImporter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
   Error Err = Error::success();
   auto *ToSrcExpr = importChecked(Err, E->getSrcExpr());
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index a819bb6dec599..80a98fe80c587 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -192,6 +192,15 @@ ExprDependence clang::computeDependence(StmtExpr *E, unsigned TemplateDepth) {
   return D & ~ExprDependence::UnexpandedPack;
 }
 
+ExprDependence clang::computeDependence(SplatVectorExpr *E) {
+  auto D = toExprDependenceAsWritten(
+               E->getTypeSourceInfo()->getType()->getDependence()) |
+           E->getSrcExpr()->getDependence();
+  if (!E->getType()->isDependentType())
+    D &= ~ExprDependence::Type;
+  return D;
+}
+
 ExprDependence clang::computeDependence(ConvertVectorExpr *E) {
   auto D = toExprDependenceAsWritten(
                E->getTypeSourceInfo()->getType()->getDependence()) |
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 9a9a76e265f6a..4644e3a86d7f0 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3845,6 +3845,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
   case SubstNonTypeTemplateParmExprClass:
   case MaterializeTemporaryExprClass:
   case ShuffleVectorExprClass:
+  case SplatVectorExprClass:
   case ConvertVectorExprClass:
   case AsTypeExprClass:
   case CXXParenListInitExprClass:
@@ -4007,6 +4008,8 @@ FPOptions Expr::getFPFeaturesInEffect(const LangOptions &LO) const {
     return BO->getFPFeaturesInEffect(LO);
   if (auto Cast = dyn_cast<CastExpr>(this))
     return Cast->getFPFeaturesInEffect(LO);
+  if (auto SplatVector = dyn_cast<SplatVectorExpr>(this))
+    return SplatVector->getFPFeaturesInEffect(LO);
   if (auto ConvertVector = dyn_cast<ConvertVectorExpr>(this))
     return ConvertVector->getFPFeaturesInEffect(LO);
   return FPOptions::defaultWithoutTrailingStorage(LO);
@@ -5684,6 +5687,24 @@ OpenACCAsteriskSizeExpr::CreateEmpty(const ASTContext &C) {
   return new (C) OpenACCAsteriskSizeExpr({}, C.IntTy);
 }
 
+SplatVectorExpr *SplatVectorExpr::CreateEmpty(const ASTContext &C,
+                                              bool hasFPFeatures) {
+  void *Mem = C.Allocate(totalSizeToAlloc<FPOptionsOverride>(hasFPFeatures),
+                         alignof(SplatVectorExpr));
+  return new (Mem) SplatVectorExpr(hasFPFeatures, EmptyShell());
+}
+
+SplatVectorExpr *SplatVectorExpr::Create(
+    const ASTContext &C, Expr *SrcExpr, TypeSourceInfo *TI, QualType DstType,
+    ExprValueKind VK, ExprObjectKind OK, SourceLocation BuiltinLoc,
+    SourceLocation RParenLoc, FPOptionsOverride FPFeatures) {
+  bool HasFPFeatures = FPFeatures.requiresTrailingStorage();
+  unsigned Size = totalSizeToAlloc<FPOptionsOverride>(HasFPFeatures);
+  void *Mem = C.Allocate(Size, alignof(SplatVectorExpr));
+  return new (Mem) SplatVectorExpr(SrcExpr, TI, DstType, VK, OK, BuiltinLoc,
+                                   RParenLoc, FPFeatures);
+}
+
 ConvertVectorExpr *ConvertVectorExpr::CreateEmpty(const ASTContext &C,
                                                   bool hasFPFeatures) {
   void *Mem = C.Allocate(totalSizeToAlloc<FPOptionsOverride>(hasFPFeatures),
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index ef071cdef66b6..bad69c3f96159 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -181,6 +181,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
   case Expr::OffsetOfExprClass:
   case Expr::CXXThrowExprClass:
   case Expr::ShuffleVectorExprClass:
+  case Expr::SplatVectorExprClass:
   case Expr::ConvertVectorExprClass:
   case Expr::IntegerLiteralClass:
   case Expr::FixedPointLiteralClass:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 9d69de2a7c6fd..b5c53e63e69d7 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -22357,6 +22357,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
   case Expr::ObjCIsaExprClass:
   case Expr::ObjCAvailabilityCheckExprClass:
   case Expr::ShuffleVectorExprClass:
+  case Expr::SplatVectorExprClass:
   case Expr::ConvertVectorExprClass:
   case Expr::BlockExprClass:
   case Expr::NoStmtClass:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index f8e6b898be250..7198bb9b5a361 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5047,6 +5047,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
   case Expr::OffsetOfExprClass:
   case Expr::PredefinedExprClass:
   case Expr::ShuffleVectorExprClass:
+  case Expr::SplatVectorExprClass:
   case Expr::ConvertVectorExprClass:
   case Expr::StmtExprClass:
   case Expr::ArrayTypeTraitExprClass:
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 877191d456b35..c4cc19e0d884a 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1987,6 +1987,14 @@ void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) {
   OS << ")";
 }
 
+void StmtPrinter::VisitSplatVectorExpr(SplatVectorExpr *Node) {
+  OS << "__builtin_splatvector(";
+  PrintExpr(Node->getSrcExpr());
+  OS << ", ";
+  Node->getType().print(OS, Policy);
+  OS << ")";
+}
+
 void StmtPrinter::VisitConvertVectorExpr(ConvertVectorExpr *Node) {
   OS << "__builtin_convertvector(";
   PrintExpr(Node->getSrcExpr());
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 00c132f1ed9e0..4ba665fff2c56 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1652,6 +1652,10 @@ void StmtProfiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *S) {
   VisitExpr(S);
 }
 
+void StmtProfiler::VisitSplatVectorExpr(const SplatVectorExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitConvertVectorExpr(const ConvertVectorExpr *S) {
   VisitExpr(S);
 }
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 843e12b371a9b..d92310f242d67 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -3357,6 +3357,12 @@ void TextNodeDumper::VisitAtomicExpr(const AtomicExpr *AE) {
   OS << ' ' << AE->getOpAsString();
 }
 
+void TextNodeDumper::VisitSplatVectorExpr(const SplatVectorExpr *S) {
+  VisitStmt(S);
+  if (S->hasStoredFPFeatures())
+    printFPOptions(S->getStoredFPFeatures());
+}
+
 void TextNodeDumper::VisitConvertVectorExpr(const ConvertVectorExpr *S) {
   VisitStmt(S);
   if (S->hasStoredFPFeatures())
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 5cbf134620e34..17de69b6260c8 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -986,6 +986,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr>
 const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr>
     cxxNullPtrLiteralExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, ChooseExpr> chooseExpr;
+const internal::VariadicDynCastAllOfMatcher<Stmt, SplatVectorExpr>
+    splatVectorExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, ConvertVectorExpr>
     convertVectorExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, CoawaitExpr>
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index a04070971f0eb..a65f04b58bebd 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -568,6 +568,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(specifiesNamespace);
   REGISTER_MATCHER(specifiesType);
   REGISTER_MATCHER(specifiesTypeLoc);
+  REGISTER_MATCHER(splatVectorExpr);
   REGISTER_MATCHER(statementCountIs);
   REGISTER_MATCHER(staticAssertDecl);
   REGISTER_MATCHER(stmt);
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 8783b43846434..cde834a71c421 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -648,6 +648,7 @@ class ScalarExprEmitter
   Value *VisitMatrixSingleSubscriptExpr(MatrixSingleSubscriptExpr *E);
   Value *VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E);
   Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
+  Value *VisitSplatVectorExpr(SplatVectorExpr *E);
   Value *VisitConvertVectorExpr(ConvertVectorExpr *E);
   Value *VisitMemberExpr(MemberExpr *E);
   Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
@@ -2058,6 +2059,92 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   return Builder.CreateShuffleVector(V1, V2, Indices, "shuffle");
 }
 
+static QualType getRawVectorElementType(ASTContext &Context,
+                                        QualType VectorTy) {
+  if (const auto *TyA = VectorTy->getAs<VectorType>())
+    return TyA->getElementType();
+  if (VectorTy->isSizelessVectorType()) {
+    // Scalable vector types (SVE, RVV) can alter the element type for Bool
+    // in order to avoid any layout issues. Effectively, it makes it harder
+    // to figure out what the actual element type was. See the comment added
+    // to Type::getSveEltType().
+    if (VectorTy->isSveVLSBuiltinType() || VectorTy->isRVVVLSBuiltinType()) {
+      const auto *BTy = VectorTy->castAs<BuiltinType>();
+      return Context.getBuiltinVectorTypeInfo(BTy).ElementType;
+    }
+    return VectorTy->getSizelessVectorEltType(Context);
+  }
+  return QualType();
+}
+
+Value *ScalarExprEmitter::VisitSplatVectorExpr(SplatVectorExpr *E) {
+  CodeGenFunction::CGFPOptionsRAII FPOptions(CGF, E);
+
+  QualType SrcType = E->getSrcExpr()->getType(),
+           DstType = E->getType();
+
+  Value *Src  = CGF.EmitScalarExpr(E->getSrcExpr());
+
+  SrcType = CGF.getContext().getCanonicalType(SrcType);
+  DstType = CGF.getContext().getCanonicalType(DstType);
+
+  assert(!SrcType->isVectorType() && !SrcType->isSizelessVectorType() &&
+         "SplatVector source type must not be a vector");
+  assert((DstType->isVectorType() || DstType->isSizelessVectorType()) &&
+         "SplatVector destination type must be a vector");
+
+  llvm::Type *SrcTy = Src->getType();
+  llvm::Type *DstTy = ConvertType(DstType);
+
+  QualType DstEltType = getRawVectorElementType(CGF.getContext(), DstType);
+  llvm::Type *DstEltTy = ConvertType(DstEltType);
+
+  Value *Splat = Builder.CreateVectorSplat(cast<llvm::VectorType>(DstTy)->getElementCount(), Src, "splatvector");
+  llvm::Type *SplatTy = Splat->getType();
+  if (SplatTy == DstTy)
+    return Splat;
+
+  if (DstEltType->isBooleanType()) {
+    assert((SrcTy->isFloatingPointTy() ||
+            isa<llvm::IntegerType>(SrcTy)) && "Unknown boolean conversion");
+
+    llvm::Value *Zero = llvm::Constant::getNullValue(SplatTy);
+    if (SrcTy->isFloatingPointTy())
+      return Builder.CreateFCmpUNE(Splat, Zero, "splattobool");
+    else
+      return Builder.CreateICmpNE(Splat, Zero, "splattobool");
+  }
+
+  // We have the arithmetic types: real int/float.
+  Value *Res = nullptr;
+
+  if (isa<llvm::IntegerType>(SrcTy)) {
+    bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
+    if (isa<llvm::IntegerType>(DstEltTy))
+      Res = Builder.CreateIntCast(Splat, DstTy, InputSigned, "splatconv");
+    else {
+      if (InputSigned)
+        Res = Builder.CreateSIToFP(Splat, DstTy, "splatconv");
+      else
+        Res = Builder.CreateUIToFP(Splat, DstTy, "splatconv");
+    }
+  } else if (isa<llvm::IntegerType>(DstEltTy)) {
+    assert(SrcTy->isFloatingPointTy() && "Unknown real conversion");
+    if (DstEltType->isSignedIntegerOrEnumerationType())
+      Res = Builder.CreateFPToSI(Splat, DstTy, "splatconv");
+    else
+      Res = Builder.CreateFPToUI(Splat, DstTy, "splatconv");
+  } else {
+    assert(SrcTy->isFloatingPointTy() && DstEltTy->isFloatingPointTy() &&
+           "Unknown real conversion");
+    if (DstEltTy->getTypeID() < SrcTy->getTypeID())
+      Res = Builder.CreateFPTrunc(Splat, DstTy, "splatconv");
+    else
+      Res = Builder.CreateFPExt(Splat, DstTy, "splatconv");
+  }
+  return Res;
+}
+
 Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
   QualType SrcType = E->getSrcExpr()->getType(),
            DstType = E->getType();
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 6ca036664094e..aeb302970dab0 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1089,6 +1089,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand,
   case tok::kw___builtin_offsetof:
   case tok::kw___builtin_choose_expr:
   case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
+  case tok::kw___builtin_splatvector:
   case tok::kw___builtin_convertvector:
   case tok::kw___builtin_COLUMN:
   case tok::kw___builtin_FILE:
@@ -2554,6 +2555,35 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
                                   ConsumeParen());
     break;
   }
+  case tok::kw___builtin_splatvector: {
+    // The first argument is an expression to be splat, followed by a comma.
+    ExprResult Expr(ParseAssignmentExpression());
+    if (Expr.isInvalid()) {
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return ExprError();
+    }
+
+    if (ExpectAndConsume(tok::comma)) {
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return ExprError();
+    }
+
+    // Second argument is the type to bitcast to.
+    TypeResult DestTy = ParseTypeName();
+    if (DestTy.isInvalid())
+      return ExprError();
+
+    // Attempt to consume the r-paren.
+    if (Tok.isNot(tok::r_paren)) {
+      Diag(Tok, diag::err_expected) << tok::r_paren;
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return ExprError();
+    }
+
+    Res = Actions.ActOnSplatVectorExpr(Expr.get(), DestTy.get(), StartLoc,
+                                       ConsumeParen());
+    break;
+  }
   case tok::kw___builtin_convertvector: {
     // The first argument is an expression to be converted, followed by a comma.
     ExprResult Expr(ParseAssignmentExpression());
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ff42d98df965c..28f8050bf97db 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6632,6 +6632,28 @@ ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
   return Result;
 }
 
+ExprResult Sema::SplatVectorExpr(Expr *E, TypeSourceInfo *TInfo,
+                                 SourceLocation BuiltinLoc,
+                                 SourceLocation RParenLoc) {
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+  QualType DstTy = TInfo->getType();
+  QualType SrcTy = E->getType();
+
+  if (SrcTy->isVectorType() || SrcTy->isSizelessVectorType())
+    return ExprError(Diag(BuiltinLoc,
+                          diag::err_splatvector_non_scalar)
+                     << E->getSourceRange());
+  if (!DstTy->isVectorType() && !DstTy->isSizelessVectorType() &&
+      !DstTy->isDependentType())
+    return ExprError(Diag(BuiltinLoc, diag::err_builtin_non_vector_type)
+                     << "second"
+                     << "__builtin_splatvector");
+
+  return SplatVectorExpr::Create(Context, E, TInfo, DstTy, VK, OK, BuiltinLoc,
+                                 RParenLoc, CurFPFeatureOverrides());
+}
+
 ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
                                    SourceLocation BuiltinLoc,
                                    SourceLocation RParenLoc) {
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 0ed5c35c40c1a..814dce0fb9933 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1299,6 +1299,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
   case Expr::ParenListExprClass:
   case Expr::ShuffleVectorExprClass:
   case Expr::StmtExprClass:
+  case Expr::SplatVectorExprClass:
   case Expr::ConvertVectorExprClass:
   case Expr::VAArgExprClass:
   case Expr::CXXParenListInitExprClass:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ed3d27b5adc27..e966513b2fc49 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7095,6 +7095,14 @@ ExprResult Sema::BuildAsTypeExpr(Expr *E, QualType DestTy,
   return new (Context) AsTypeExpr(E, DestTy, VK, OK, BuiltinLoc, RParenLoc);
 }
 
+ExprResult Sema::ActOnSplatVectorExpr(Expr *E, ParsedType ParsedDestTy,
+                                      SourceLocation BuiltinLoc,
+                                      SourceLocation RParenLoc) {
+  TypeSourceInfo *TInfo;
+  GetTypeFromParser(ParsedDestTy, &TInfo);
+  return SplatVectorExpr(E, TInfo, BuiltinLoc, RParenLoc);
+}
+
 ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy,
                                         SourceLocation BuiltinLoc,
                                         SourceLocation RParenLoc) {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 0725664a4e050..04120baaa5aac 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4059,6 +4059,13 @@ class TreeTransform {
     return SemaRef.BuiltinShuffleVector(cast<CallExpr>(TheCall.get()));
   }
 
+  /// Build a new splat vector expression.
+  ExprResult RebuildSplatVectorExpr(SourceLocation BuiltinLoc,
+                                    Expr *SrcExpr, TypeSourceInfo *DstTInfo,
+                                    SourceLocation RParenLoc) {
+    return SemaRef.SplatVectorExpr(SrcExpr, DstTInfo, BuiltinLoc, RParenLoc);
+  }
+
   /// Build a new convert vector expression.
   ExprResult RebuildConvertVectorExpr(SourceLocation BuiltinLoc,
                                       Expr *SrcExpr, TypeSourceInfo *DstTInfo,
@@ -17652,6 +17659,27 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) {
                                                E->getRParenLoc());
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformSplatVectorExpr(SplatVectorExpr *E) {
+  ExprResult SrcExpr = getDerived().TransformExpr(E->getSrcExpr());
+  if (SrcExpr.isInvalid())
+    return ExprError();
+
+  TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo());
+  if (!Type)
+    return ExprError();
+
+  if (!getDerived().AlwaysRebuild() &&
+      Type == E->getTypeSourceInfo() &&
+      SrcExpr.get() == E->getSrcExpr())
+    return E;
+
+  return getDerived().RebuildSplatVectorExpr(E->getBuiltinLoc(),
+                                             SrcExpr.get(), Type,
+                                             E->getRParenLoc());
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformConvertVectorExpr(ConvertVectorExpr *E) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 6cde6c1816dc7..dc6235bda826c 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1439,6 +1439,19 @@ void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   E->setRParenLoc(readSourceLocation());
 }
 
+void ASTStmtReader::VisitSplatVectorExpr(SplatVectorExpr *E) {
+  VisitExpr(E);
+  bool HasFPFeatures = CurrentUnpackingBits->getNextBit();
+  assert(HasFPFeatures == E->hasStoredFPFeatures());
+  E->BuiltinLoc = readSourceLocation();
+  E->RParenLoc = readSourceLocation();
+  E->TInfo = readTypeSourceInfo();
+  E->SrcExpr = Record.readSubExpr();
+  if (HasFPFeatures)
+    E->setStoredFPFeatures(
+        FPOptionsOverride::getFromOpaqueInt(Record.readInt()));
+}
+
 void ASTStmtReader::VisitConvertVectorExpr(ConvertVectorExpr *E) {
   VisitExpr(E);
   bool HasFPFeatures = CurrentUnpackingBits->getNextBit();
@@ -3517,6 +3530,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       S = new (Context) ShuffleVectorExpr(Empty);
       break;
 
+    case EXPR_SPLAT_VECTOR: {
+      BitsUnpacker SplatVectorExprBits(Record[ASTStmtReader::NumStmtFields]);
+      SplatVectorExprBits.advance(ASTStmtReader::NumExprBits);
+      bool HasFPFeatures = SplatVectorExprBits.getNextBit();
+      S = SplatVectorExpr::CreateEmpty(Context, HasFPFeatures);
+      break;
+    }
+
     case EXPR_CONVERT_VECTOR: {
       BitsUnpacker ConvertVectorExprBits(Record[ASTStmtReader::NumStmtFields]);
       ConvertVectorExprBits.advance(ASTStmtReader::NumExprBits);
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 10443d42df8c0..06487b9e41156 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1390,6 +1390,19 @@ void ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
   Code = serialization::EXPR_SHUFFLE_VECTOR;
 }
 
+void ASTStmtWriter::VisitSplatVectorExpr(SplatVectorExpr *E) {
+  VisitExpr(E);
+  bool HasFPFeatures = E->hasStoredFPFeatures();
+  CurrentPackingBits.addBit(HasFPFeatures);
+  Record.AddSourceLocation(E->getBuiltinLoc());
+  Record.AddSourceLocation(E->getRParenLoc());
+  Record.AddTypeSourceInfo(E->getTypeSourceInfo());
+  Record.AddStmt(E->getSrcExpr());
+  Code = serialization::EXPR_SPLAT_VECTOR;
+  if (HasFPFeatures)
+    Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt());
+}
+
 void ASTStmtWriter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
   VisitExpr(E);
   bool HasFPFeatures = E->hasStoredFPFeatures();
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 7669b65818272..aa1d0eb5b7002 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1903,6 +1903,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::ObjCSelectorExprClass:
     case Stmt::ParenListExprClass:
     case Stmt::ShuffleVectorExprClass:
+    case Stmt::SplatVectorExprClass:
     case Stmt::ConvertVectorExprClass:
     case Stmt::VAArgExprClass:
     case Stmt::CUDAKernelCallExprClass:
diff --git a/clang/test/AST/ast-dump-fpfeatures.cpp b/clang/test/AST/ast-dump-fpfeatures.cpp
index eeead3462c0ec..d1cf1b8e6cb13 100644
--- a/clang/test/AST/ast-dump-fpfeatures.cpp
+++ b/clang/test/AST/ast-dump-fpfeatures.cpp
@@ -19,6 +19,15 @@ vector2float no_fpfeatures_func_01(vector2double x) {
   return __builtin_convertvector(x, vector2float);
 }
 
+// CHECK-LABEL: FunctionDecl {{.*}} no_fpfeatures_func_01a 'vector2float (double)'
+// CHECK:         CompoundStmt {{.*\>$}}
+// CHECK:           ReturnStmt
+// CHECK:             SplatVectorExpr {{.*}} 'vector2float':'__attribute__((__vector_size__(2 * sizeof(float)))) float'{{$}}
+
+vector2float no_fpfeatures_func_01a(double x) {
+  return __builtin_splatvector(x, vector2float);
+}
+
 float func_01(float x);
 
 template <typename T>
@@ -270,3 +279,13 @@ float func_23(float x, float y) {
 vector2float func_24(vector2double x) {
   return __builtin_convertvector(x, vector2float);
 }
+
+// CHECK-LABEL: FunctionDecl {{.*}} func_24a 'vector2float (double)'
+// CHECK:         CompoundStmt {{.*}} FPContractMode=2 ConstRoundingMode=towardzero
+// CHECK:           ReturnStmt
+// CHECK:             SplatVectorExpr {{.*}} FPContractMode=2 ConstRoundingMode=towardzero
+
+#pragma STDC FENV_ROUND FE_TOWARDZERO
+vector2float func_24a(double x) {
+  return __builtin_splatvector(x, vector2float);
+}
diff --git a/clang/test/CodeGen/pragma-fenv_access.c b/clang/test/CodeGen/pragma-fenv_access.c
index 76c38f957d632..feaf8ca845112 100644
--- a/clang/test/CodeGen/pragma-fenv_access.c
+++ b/clang/test/CodeGen/pragma-fenv_access.c
@@ -287,3 +287,43 @@ vector3ulong func_23(vector3float x) {
 }
 // CHECK-LABEL: @func_23
 // STRICT: call <3 x i64> @llvm.experimental.constrained.fptoui.v3i64.v3f32(<3 x float> {{.*}}, metadata !"fpexcept.ignore")
+
+typedef float  vector4float  __attribute__((__vector_size__(16)));
+vector4float func_26(double x) {
+  #pragma STDC FENV_ROUND FE_UPWARD
+  return __builtin_splatvector(x, vector4float);
+}
+// CHECK-LABEL: @func_26
+// STRICT: call <4 x float> @llvm.experimental.constrained.fptrunc.v4f32.v4f64(<4 x double> {{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+
+typedef double vector8double __attribute__((__vector_size__(64)));
+vector8double func_27(short x) {
+  #pragma STDC FENV_ROUND FE_TOWARDZERO
+  return __builtin_splatvector(x, vector8double);
+}
+// CHECK-LABEL: @func_27
+// STRICT: call <8 x double> @llvm.experimental.constrained.sitofp.v8f64.v8i16(<8 x i16> {{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict")
+
+typedef double vector16double __attribute__((__vector_size__(128)));
+vector16double func_28(unsigned x) {
+  #pragma STDC FENV_ROUND FE_DOWNWARD
+  return __builtin_splatvector(x, vector16double);
+}
+// CHECK-LABEL: @func_28
+// STRICT: call <16 x double> @llvm.experimental.constrained.uitofp.v16f64.v16i32(<16 x i32> {{.*}}, metadata !"round.downward", metadata !"fpexcept.strict")
+
+typedef char vector2char __attribute__((__vector_size__(2)));
+vector2char func_29(float x) {
+  #pragma float_control(except, off)
+  return __builtin_splatvector(x, vector2char);
+}
+// CHECK-LABEL: @func_29
+// STRICT: call <2 x i8> @llvm.experimental.constrained.fptosi.v2i8.v2f32(<2 x float> {{.*}}, metadata !"fpexcept.ignore")
+
+typedef unsigned long long vector3ulong __attribute__((__vector_size__(24)));
+vector3ulong func_30(float x) {
+  #pragma float_control(except, off)
+  return __builtin_splatvector(x, vector3ulong);
+}
+// CHECK-LABEL: @func_30
+// STRICT: call <3 x i64> @llvm.experimental.constrained.fptoui.v3i64.v3f32(<3 x float> {{.*}}, metadata !"fpexcept.ignore")
diff --git a/clang/test/CodeGen/splatvector-sizeless-aarch64.c b/clang/test/CodeGen/splatvector-sizeless-aarch64.c
new file mode 100644
index 0000000000000..f2739271f6ad5
--- /dev/null
+++ b/clang/test/CodeGen/splatvector-sizeless-aarch64.c
@@ -0,0 +1,518 @@
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sve -emit-llvm -x c++ %s -o - | FileCheck %s
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+__SVBool_t splat_bool_imm___SVBool_t(void) {
+  return __builtin_splatvector(true, __SVBool_t);
+  // CHECK-LABEL: @splat_bool_imm___SVBool_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__SVBool_t splat_int_imm___SVBool_t(void) {
+  return __builtin_splatvector(-1, __SVBool_t);
+  // CHECK-LABEL: @splat_int_imm___SVBool_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__SVBool_t splat_uint_imm___SVBool_t(void) {
+  return __builtin_splatvector(1U, __SVBool_t);
+  // CHECK-LABEL: @splat_uint_imm___SVBool_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__SVBool_t splat_float_imm___SVBool_t(void) {
+  return __builtin_splatvector(1.0f, __SVBool_t);
+  // CHECK-LABEL: @splat_float_imm___SVBool_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__SVBool_t splat_double_imm___SVBool_t(void) {
+  return __builtin_splatvector(1.0, __SVBool_t);
+  // CHECK-LABEL: @splat_double_imm___SVBool_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__SVBool_t splat_bool_var___SVBool_t(bool x) {
+  return __builtin_splatvector(x, __SVBool_t);
+  // CHECK-LABEL: @splat_bool_var___SVBool_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[SPLAT]]
+}
+
+__SVBool_t splat_int_var___SVBool_t(int x) {
+  return __builtin_splatvector(x, __SVBool_t);
+  // CHECK-LABEL: @splat_int_var___SVBool_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = icmp ne <vscale x {{[0-9]*}} x i32> %splatvector.splat, zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[CONV]]
+}
+
+__SVBool_t splat_uint_var___SVBool_t(unsigned x) {
+  return __builtin_splatvector(x, __SVBool_t);
+  // CHECK-LABEL: @splat_uint_var___SVBool_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = icmp ne <vscale x {{[0-9]*}} x i32> %[[SPLAT]], zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[CONV]]
+}
+
+__SVBool_t splat_float_var___SVBool_t(float x) {
+  return __builtin_splatvector(x, __SVBool_t);
+  // CHECK-LABEL: @splat_float_var___SVBool_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fcmp une <vscale x {{[0-9]*}} x float> %[[SPLAT]], zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[CONV]]
+}
+
+__SVBool_t splat_double_var___SVBool_t(double x) {
+  return __builtin_splatvector(x, __SVBool_t);
+  // CHECK-LABEL: @splat_double_var___SVBool_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fcmp une <vscale x {{[0-9]*}} x double> %[[SPLAT]], zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[CONV]]
+}
+
+__SVInt64_t splat_bool_imm___SVInt64_t(void) {
+  return __builtin_splatvector(true, __SVInt64_t);
+  // CHECK-LABEL: @splat_bool_imm___SVInt64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__SVInt64_t splat_int_imm___SVInt64_t(void) {
+  return __builtin_splatvector(-1, __SVInt64_t);
+  // CHECK-LABEL: @splat_int_imm___SVInt64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 -1)
+}
+
+__SVInt64_t splat_uint_imm___SVInt64_t(void) {
+  return __builtin_splatvector(1U, __SVInt64_t);
+  // CHECK-LABEL: @splat_uint_imm___SVInt64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__SVInt64_t splat_float_imm___SVInt64_t(void) {
+  return __builtin_splatvector(1.0f, __SVInt64_t);
+  // CHECK-LABEL: @splat_float_imm___SVInt64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__SVInt64_t splat_double_imm___SVInt64_t(void) {
+  return __builtin_splatvector(1.0, __SVInt64_t);
+  // CHECK-LABEL: @splat_double_imm___SVInt64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__SVInt64_t splat_bool_var___SVInt64_t(bool x) {
+  return __builtin_splatvector(x, __SVInt64_t);
+  // CHECK-LABEL: @splat_bool_var___SVInt64_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <vscale x {{[0-9]*}} x i1> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVInt64_t splat_int_var___SVInt64_t(int x) {
+  return __builtin_splatvector(x, __SVInt64_t);
+  // CHECK-LABEL: @splat_int_var___SVInt64_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sext <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVInt64_t splat_uint_var___SVInt64_t(unsigned x) {
+  return __builtin_splatvector(x, __SVInt64_t);
+  // CHECK-LABEL: @splat_uint_var___SVInt64_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVInt64_t splat_float_var___SVInt64_t(float x) {
+  return __builtin_splatvector(x, __SVInt64_t);
+  // CHECK-LABEL: @splat_float_var___SVInt64_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptosi <vscale x {{[0-9]*}} x float> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVInt64_t splat_double_var___SVInt64_t(double x) {
+  return __builtin_splatvector(x, __SVInt64_t);
+  // CHECK-LABEL: @splat_double_var___SVInt64_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptosi <vscale x {{[0-9]*}} x double> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVUint64_t splat_bool_imm___SVUint64_t(void) {
+  return __builtin_splatvector(true, __SVUint64_t);
+  // CHECK-LABEL: @splat_bool_imm___SVUint64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__SVUint64_t splat_int_imm___SVUint64_t(void) {
+  return __builtin_splatvector(-1, __SVUint64_t);
+  // CHECK-LABEL: @splat_int_imm___SVUint64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 -1)
+}
+
+__SVUint64_t splat_uint_imm___SVUint64_t(void) {
+  return __builtin_splatvector(1U, __SVUint64_t);
+  // CHECK-LABEL: @splat_uint_imm___SVUint64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__SVUint64_t splat_float_imm___SVUint64_t(void) {
+  return __builtin_splatvector(1.0f, __SVUint64_t);
+  // CHECK-LABEL: @splat_float_imm___SVUint64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__SVUint64_t splat_double_imm___SVUint64_t(void) {
+  return __builtin_splatvector(1.0, __SVUint64_t);
+  // CHECK-LABEL: @splat_double_imm___SVUint64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__SVUint64_t splat_bool_var___SVUint64_t(bool x) {
+  return __builtin_splatvector(x, __SVUint64_t);
+  // CHECK-LABEL: @splat_bool_var___SVUint64_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <vscale x {{[0-9]*}} x i1> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVUint64_t splat_int_var___SVUint64_t(int x) {
+  return __builtin_splatvector(x, __SVUint64_t);
+  // CHECK-LABEL: @splat_int_var___SVUint64_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sext <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVUint64_t splat_uint_var___SVUint64_t(unsigned x) {
+  return __builtin_splatvector(x, __SVUint64_t);
+  // CHECK-LABEL: @splat_uint_var___SVUint64_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVUint64_t splat_float_var___SVUint64_t(float x) {
+  return __builtin_splatvector(x, __SVUint64_t);
+  // CHECK-LABEL: @splat_float_var___SVUint64_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptoui <vscale x {{[0-9]*}} x float> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVUint64_t splat_double_var___SVUint64_t(double x) {
+  return __builtin_splatvector(x, __SVUint64_t);
+  // CHECK-LABEL: @splat_double_var___SVUint64_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptoui <vscale x {{[0-9]*}} x double> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__SVFloat32_t splat_bool_imm___SVFloat32_t(void) {
+  return __builtin_splatvector(true, __SVFloat32_t);
+  // CHECK-LABEL: @splat_bool_imm___SVFloat32_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float 1.000000e+00)
+}
+
+__SVFloat32_t splat_int_imm___SVFloat32_t(void) {
+  return __builtin_splatvector(-1, __SVFloat32_t);
+  // CHECK-LABEL: @splat_int_imm___SVFloat32_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float -1.000000e+00)
+}
+
+__SVFloat32_t splat_uint_imm___SVFloat32_t(void) {
+  return __builtin_splatvector(1U, __SVFloat32_t);
+  // CHECK-LABEL: @splat_uint_imm___SVFloat32_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float 1.000000e+00)
+}
+
+__SVFloat32_t splat_float_imm___SVFloat32_t(void) {
+  return __builtin_splatvector(1.0f, __SVFloat32_t);
+  // CHECK-LABEL: @splat_float_imm___SVFloat32_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float 1.000000e+00)
+}
+
+__SVFloat32_t splat_double_imm___SVFloat32_t(void) {
+  return __builtin_splatvector(1.0, __SVFloat32_t);
+  // CHECK-LABEL: @splat_double_imm___SVFloat32_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float 1.000000e+00)
+}
+
+__SVFloat32_t splat_bool_var___SVFloat32_t(bool x) {
+  return __builtin_splatvector(x, __SVFloat32_t);
+  // CHECK-LABEL: @splat_bool_var___SVFloat32_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <vscale x {{[0-9]*}} x i1> %[[SPLAT]] to <vscale x {{[0-9]*}} x float>
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[CONV]]
+}
+
+__SVFloat32_t splat_int_var___SVFloat32_t(int x) {
+  return __builtin_splatvector(x, __SVFloat32_t);
+  // CHECK-LABEL: @splat_int_var___SVFloat32_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sitofp <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x float>
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[CONV]]
+}
+
+__SVFloat32_t splat_uint_var___SVFloat32_t(unsigned x) {
+  return __builtin_splatvector(x, __SVFloat32_t);
+  // CHECK-LABEL: @splat_uint_var___SVFloat32_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x float>
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[CONV]]
+}
+
+__SVFloat32_t splat_float_var___SVFloat32_t(float x) {
+  return __builtin_splatvector(x, __SVFloat32_t);
+  // CHECK-LABEL: @splat_float_var___SVFloat32_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[SPLAT]]
+}
+
+__SVFloat32_t splat_double_var___SVFloat32_t(double x) {
+  return __builtin_splatvector(x, __SVFloat32_t);
+  // CHECK-LABEL: @splat_double_var___SVFloat32_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptrunc <vscale x {{[0-9]*}} x double> %[[SPLAT]] to <vscale x {{[0-9]*}} x float>
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[CONV]]
+}
+
+__SVFloat64_t splat_bool_imm___SVFloat64_t(void) {
+  return __builtin_splatvector(true, __SVFloat64_t);
+  // CHECK-LABEL: @splat_bool_imm___SVFloat64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double 1.000000e+00)
+}
+
+__SVFloat64_t splat_int_imm___SVFloat64_t(void) {
+  return __builtin_splatvector(-1, __SVFloat64_t);
+  // CHECK-LABEL: @splat_int_imm___SVFloat64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double -1.000000e+00)
+}
+
+__SVFloat64_t splat_uint_imm___SVFloat64_t(void) {
+  return __builtin_splatvector(1U, __SVFloat64_t);
+  // CHECK-LABEL: @splat_uint_imm___SVFloat64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double 1.000000e+00)
+}
+
+__SVFloat64_t splat_float_imm___SVFloat64_t(void) {
+  return __builtin_splatvector(1.0f, __SVFloat64_t);
+  // CHECK-LABEL: @splat_float_imm___SVFloat64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double 1.000000e+00)
+}
+
+__SVFloat64_t splat_double_imm___SVFloat64_t(void) {
+  return __builtin_splatvector(1.0, __SVFloat64_t);
+  // CHECK-LABEL: @splat_double_imm___SVFloat64_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double 1.000000e+00)
+}
+
+__SVFloat64_t splat_bool_var___SVFloat64_t(bool x) {
+  return __builtin_splatvector(x, __SVFloat64_t);
+  // CHECK-LABEL: @splat_bool_var___SVFloat64_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <vscale x {{[0-9]*}} x i1> %[[SPLAT]] to <vscale x {{[0-9]*}} x double>
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[CONV]]
+}
+
+__SVFloat64_t splat_int_var___SVFloat64_t(int x) {
+  return __builtin_splatvector(x, __SVFloat64_t);
+  // CHECK-LABEL: @splat_int_var___SVFloat64_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sitofp <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x double>
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[CONV]]
+}
+
+__SVFloat64_t splat_uint_var___SVFloat64_t(unsigned x) {
+  return __builtin_splatvector(x, __SVFloat64_t);
+  // CHECK-LABEL: @splat_uint_var___SVFloat64_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x double>
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[CONV]]
+}
+
+__SVFloat64_t splat_float_var___SVFloat64_t(float x) {
+  return __builtin_splatvector(x, __SVFloat64_t);
+  // CHECK-LABEL: @splat_float_var___SVFloat64_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fpext <vscale x {{[0-9]*}} x float> %[[SPLAT]] to <vscale x {{[0-9]*}} x double>
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[CONV]]
+}
+
+__SVFloat64_t splat_double_var___SVFloat64_t(double x) {
+  return __builtin_splatvector(x, __SVFloat64_t);
+  // CHECK-LABEL: @splat_double_var___SVFloat64_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[SPLAT]]
+}
+
+__SVFloat32_t splat_flt_trunc(double x) {
+  return __builtin_splatvector(x, __SVFloat32_t);
+  // CHECK-LABEL: @splat_flt_trunc
+  // CHECK: fptrunc <vscale x {{[0-9]*}} x double> %{{.*}} to <vscale x {{[0-9]*}} x float>
+}
+
+__SVFloat64_t splat_flt_ext(float x) {
+  return __builtin_splatvector(x, __SVFloat64_t);
+  // CHECK-LABEL: @splat_flt_ext
+  // CHECK: fpext <vscale x {{[0-9]*}} x float> %{{.*}} to <vscale x {{[0-9]*}} x double>
+}
+
+__SVInt64_t splat_flt_tosi(float x) {
+  return __builtin_splatvector(x, __SVInt64_t);
+  // CHECK-LABEL: @splat_flt_tosi
+  // CHECK: fptosi <vscale x {{[0-9]*}} x float> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__SVUint64_t splat_flt_toui(float x) {
+  return __builtin_splatvector(x, __SVUint64_t);
+  // CHECK-LABEL: @splat_flt_toui
+  // CHECK: fptoui <vscale x {{[0-9]*}} x float> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__SVUint64_t splat_fltd_toui(double x) {
+  return __builtin_splatvector(x, __SVUint64_t);
+  // CHECK-LABEL: @splat_fltd_toui
+  // CHECK: fptoui <vscale x {{[0-9]*}} x double> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__SVUint64_t splat_int_zext(unsigned short x) {
+  return __builtin_splatvector(x, __SVUint64_t);
+  // CHECK-LABEL: @splat_int_zext
+  // CHECK: zext <vscale x {{[0-9]*}} x i16> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__SVInt64_t splat_int_sext(short x) {
+  return __builtin_splatvector(x, __SVInt64_t);
+  // CHECK-LABEL: @splat_int_sext
+  // CHECK: sext <vscale x {{[0-9]*}} x i16> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__SVFloat32_t splat_int_tofp(short x) {
+  return __builtin_splatvector(x, __SVFloat32_t);
+  // CHECK-LABEL: @splat_int_tofp
+  // CHECK: sitofp <vscale x {{[0-9]*}} x i16> %{{.*}} to <vscale x {{[0-9]*}} x float>
+}
+
+__SVFloat32_t splat_uint_tofp(unsigned short x) {
+  return __builtin_splatvector(x, __SVFloat32_t);
+  // CHECK-LABEL: @splat_uint_tofp
+  // CHECK: uitofp <vscale x {{[0-9]*}} x i16> %{{.*}} to <vscale x {{[0-9]*}} x float>
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+template<typename T>
+T splat_int_toT(long x) {
+  return __builtin_splatvector(x, T);
+}
+
+extern "C" {
+  __SVFloat64_t splat_int_toT_fp(long x) {
+    // CHECK-LABEL: @splat_int_toT_fp
+    // CHECK: sitofp <vscale x {{[0-9]*}} x i64> %{{.*}} to <vscale x {{[0-9]*}} x double>
+    return splat_int_toT<__SVFloat64_t>(x);
+  }
+}
+#else
+__SVFloat64_t splat_int_toT_fp(long x) {
+  return __builtin_splatvector(x, __SVFloat64_t);
+}
+#endif
diff --git a/clang/test/CodeGen/splatvector-sizeless-riscv.c b/clang/test/CodeGen/splatvector-sizeless-riscv.c
new file mode 100644
index 0000000000000..ca8090c1f1760
--- /dev/null
+++ b/clang/test/CodeGen/splatvector-sizeless-riscv.c
@@ -0,0 +1,518 @@
+// RUN: %clang_cc1 -triple riscv64 -target-feature +zve64d -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +zve64d -emit-llvm -x c++ %s -o - | FileCheck %s
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+__rvv_bool1_t splat_bool_imm___rvv_bool1_t(void) {
+  return __builtin_splatvector(true, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_bool_imm___rvv_bool1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__rvv_bool1_t splat_int_imm___rvv_bool1_t(void) {
+  return __builtin_splatvector(-1, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_int_imm___rvv_bool1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__rvv_bool1_t splat_uint_imm___rvv_bool1_t(void) {
+  return __builtin_splatvector(1U, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_uint_imm___rvv_bool1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__rvv_bool1_t splat_float_imm___rvv_bool1_t(void) {
+  return __builtin_splatvector(1.0f, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_float_imm___rvv_bool1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__rvv_bool1_t splat_double_imm___rvv_bool1_t(void) {
+  return __builtin_splatvector(1.0, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_double_imm___rvv_bool1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> splat (i1 true)
+}
+
+__rvv_bool1_t splat_bool_var___rvv_bool1_t(bool x) {
+  return __builtin_splatvector(x, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_bool_var___rvv_bool1_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[SPLAT]]
+}
+
+__rvv_bool1_t splat_int_var___rvv_bool1_t(int x) {
+  return __builtin_splatvector(x, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_int_var___rvv_bool1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = icmp ne <vscale x {{[0-9]*}} x i32> %splatvector.splat, zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[CONV]]
+}
+
+__rvv_bool1_t splat_uint_var___rvv_bool1_t(unsigned x) {
+  return __builtin_splatvector(x, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_uint_var___rvv_bool1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = icmp ne <vscale x {{[0-9]*}} x i32> %[[SPLAT]], zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[CONV]]
+}
+
+__rvv_bool1_t splat_float_var___rvv_bool1_t(float x) {
+  return __builtin_splatvector(x, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_float_var___rvv_bool1_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fcmp une <vscale x {{[0-9]*}} x float> %[[SPLAT]], zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[CONV]]
+}
+
+__rvv_bool1_t splat_double_var___rvv_bool1_t(double x) {
+  return __builtin_splatvector(x, __rvv_bool1_t);
+  // CHECK-LABEL: @splat_double_var___rvv_bool1_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fcmp une <vscale x {{[0-9]*}} x double> %[[SPLAT]], zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x i1> %[[CONV]]
+}
+
+__rvv_int64m1_t splat_bool_imm___rvv_int64m1_t(void) {
+  return __builtin_splatvector(true, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_bool_imm___rvv_int64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__rvv_int64m1_t splat_int_imm___rvv_int64m1_t(void) {
+  return __builtin_splatvector(-1, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_int_imm___rvv_int64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 -1)
+}
+
+__rvv_int64m1_t splat_uint_imm___rvv_int64m1_t(void) {
+  return __builtin_splatvector(1U, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_uint_imm___rvv_int64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__rvv_int64m1_t splat_float_imm___rvv_int64m1_t(void) {
+  return __builtin_splatvector(1.0f, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_float_imm___rvv_int64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__rvv_int64m1_t splat_double_imm___rvv_int64m1_t(void) {
+  return __builtin_splatvector(1.0, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_double_imm___rvv_int64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__rvv_int64m1_t splat_bool_var___rvv_int64m1_t(bool x) {
+  return __builtin_splatvector(x, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_bool_var___rvv_int64m1_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <vscale x {{[0-9]*}} x i1> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_int64m1_t splat_int_var___rvv_int64m1_t(int x) {
+  return __builtin_splatvector(x, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_int_var___rvv_int64m1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sext <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_int64m1_t splat_uint_var___rvv_int64m1_t(unsigned x) {
+  return __builtin_splatvector(x, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_uint_var___rvv_int64m1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_int64m1_t splat_float_var___rvv_int64m1_t(float x) {
+  return __builtin_splatvector(x, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_float_var___rvv_int64m1_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptosi <vscale x {{[0-9]*}} x float> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_int64m1_t splat_double_var___rvv_int64m1_t(double x) {
+  return __builtin_splatvector(x, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_double_var___rvv_int64m1_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptosi <vscale x {{[0-9]*}} x double> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_uint64m1_t splat_bool_imm___rvv_uint64m1_t(void) {
+  return __builtin_splatvector(true, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_bool_imm___rvv_uint64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__rvv_uint64m1_t splat_int_imm___rvv_uint64m1_t(void) {
+  return __builtin_splatvector(-1, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_int_imm___rvv_uint64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 -1)
+}
+
+__rvv_uint64m1_t splat_uint_imm___rvv_uint64m1_t(void) {
+  return __builtin_splatvector(1U, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_uint_imm___rvv_uint64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__rvv_uint64m1_t splat_float_imm___rvv_uint64m1_t(void) {
+  return __builtin_splatvector(1.0f, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_float_imm___rvv_uint64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__rvv_uint64m1_t splat_double_imm___rvv_uint64m1_t(void) {
+  return __builtin_splatvector(1.0, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_double_imm___rvv_uint64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> splat (i64 1)
+}
+
+__rvv_uint64m1_t splat_bool_var___rvv_uint64m1_t(bool x) {
+  return __builtin_splatvector(x, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_bool_var___rvv_uint64m1_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <vscale x {{[0-9]*}} x i1> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_uint64m1_t splat_int_var___rvv_uint64m1_t(int x) {
+  return __builtin_splatvector(x, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_int_var___rvv_uint64m1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sext <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_uint64m1_t splat_uint_var___rvv_uint64m1_t(unsigned x) {
+  return __builtin_splatvector(x, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_uint_var___rvv_uint64m1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_uint64m1_t splat_float_var___rvv_uint64m1_t(float x) {
+  return __builtin_splatvector(x, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_float_var___rvv_uint64m1_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptoui <vscale x {{[0-9]*}} x float> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_uint64m1_t splat_double_var___rvv_uint64m1_t(double x) {
+  return __builtin_splatvector(x, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_double_var___rvv_uint64m1_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptoui <vscale x {{[0-9]*}} x double> %[[SPLAT]] to <vscale x {{[0-9]*}} x i64>
+  // CHECK: ret <vscale x {{[0-9]*}} x i64> %[[CONV]]
+}
+
+__rvv_float32m1_t splat_bool_imm___rvv_float32m1_t(void) {
+  return __builtin_splatvector(true, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_bool_imm___rvv_float32m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float 1.000000e+00)
+}
+
+__rvv_float32m1_t splat_int_imm___rvv_float32m1_t(void) {
+  return __builtin_splatvector(-1, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_int_imm___rvv_float32m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float -1.000000e+00)
+}
+
+__rvv_float32m1_t splat_uint_imm___rvv_float32m1_t(void) {
+  return __builtin_splatvector(1U, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_uint_imm___rvv_float32m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float 1.000000e+00)
+}
+
+__rvv_float32m1_t splat_float_imm___rvv_float32m1_t(void) {
+  return __builtin_splatvector(1.0f, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_float_imm___rvv_float32m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float 1.000000e+00)
+}
+
+__rvv_float32m1_t splat_double_imm___rvv_float32m1_t(void) {
+  return __builtin_splatvector(1.0, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_double_imm___rvv_float32m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x float> splat (float 1.000000e+00)
+}
+
+__rvv_float32m1_t splat_bool_var___rvv_float32m1_t(bool x) {
+  return __builtin_splatvector(x, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_bool_var___rvv_float32m1_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <vscale x {{[0-9]*}} x i1> %[[SPLAT]] to <vscale x {{[0-9]*}} x float>
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[CONV]]
+}
+
+__rvv_float32m1_t splat_int_var___rvv_float32m1_t(int x) {
+  return __builtin_splatvector(x, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_int_var___rvv_float32m1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sitofp <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x float>
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[CONV]]
+}
+
+__rvv_float32m1_t splat_uint_var___rvv_float32m1_t(unsigned x) {
+  return __builtin_splatvector(x, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_uint_var___rvv_float32m1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x float>
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[CONV]]
+}
+
+__rvv_float32m1_t splat_float_var___rvv_float32m1_t(float x) {
+  return __builtin_splatvector(x, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_float_var___rvv_float32m1_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[SPLAT]]
+}
+
+__rvv_float32m1_t splat_double_var___rvv_float32m1_t(double x) {
+  return __builtin_splatvector(x, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_double_var___rvv_float32m1_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptrunc <vscale x {{[0-9]*}} x double> %[[SPLAT]] to <vscale x {{[0-9]*}} x float>
+  // CHECK: ret <vscale x {{[0-9]*}} x float> %[[CONV]]
+}
+
+__rvv_float64m1_t splat_bool_imm___rvv_float64m1_t(void) {
+  return __builtin_splatvector(true, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_bool_imm___rvv_float64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double 1.000000e+00)
+}
+
+__rvv_float64m1_t splat_int_imm___rvv_float64m1_t(void) {
+  return __builtin_splatvector(-1, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_int_imm___rvv_float64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double -1.000000e+00)
+}
+
+__rvv_float64m1_t splat_uint_imm___rvv_float64m1_t(void) {
+  return __builtin_splatvector(1U, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_uint_imm___rvv_float64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double 1.000000e+00)
+}
+
+__rvv_float64m1_t splat_float_imm___rvv_float64m1_t(void) {
+  return __builtin_splatvector(1.0f, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_float_imm___rvv_float64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double 1.000000e+00)
+}
+
+__rvv_float64m1_t splat_double_imm___rvv_float64m1_t(void) {
+  return __builtin_splatvector(1.0, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_double_imm___rvv_float64m1_t
+  // CHECK: ret <vscale x {{[0-9]*}} x double> splat (double 1.000000e+00)
+}
+
+__rvv_float64m1_t splat_bool_var___rvv_float64m1_t(bool x) {
+  return __builtin_splatvector(x, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_bool_var___rvv_float64m1_t
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i1> %[[INSERT]], <vscale x {{[0-9]*}} x i1> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <vscale x {{[0-9]*}} x i1> %[[SPLAT]] to <vscale x {{[0-9]*}} x double>
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[CONV]]
+}
+
+__rvv_float64m1_t splat_int_var___rvv_float64m1_t(int x) {
+  return __builtin_splatvector(x, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_int_var___rvv_float64m1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sitofp <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x double>
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[CONV]]
+}
+
+__rvv_float64m1_t splat_uint_var___rvv_float64m1_t(unsigned x) {
+  return __builtin_splatvector(x, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_uint_var___rvv_float64m1_t
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x i32> %[[INSERT]], <vscale x {{[0-9]*}} x i32> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <vscale x {{[0-9]*}} x i32> %[[SPLAT]] to <vscale x {{[0-9]*}} x double>
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[CONV]]
+}
+
+__rvv_float64m1_t splat_float_var___rvv_float64m1_t(float x) {
+  return __builtin_splatvector(x, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_float_var___rvv_float64m1_t
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x float> %[[INSERT]], <vscale x {{[0-9]*}} x float> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fpext <vscale x {{[0-9]*}} x float> %[[SPLAT]] to <vscale x {{[0-9]*}} x double>
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[CONV]]
+}
+
+__rvv_float64m1_t splat_double_var___rvv_float64m1_t(double x) {
+  return __builtin_splatvector(x, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_double_var___rvv_float64m1_t
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <vscale x {{[0-9]*}} x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <vscale x {{[0-9]*}} x double> %[[INSERT]], <vscale x {{[0-9]*}} x double> poison, <vscale x {{[0-9]*}} x i32> zeroinitializer
+  // CHECK: ret <vscale x {{[0-9]*}} x double> %[[SPLAT]]
+}
+
+__rvv_float32m1_t splat_flt_trunc(double x) {
+  return __builtin_splatvector(x, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_flt_trunc
+  // CHECK: fptrunc <vscale x {{[0-9]*}} x double> %{{.*}} to <vscale x {{[0-9]*}} x float>
+}
+
+__rvv_float64m1_t splat_flt_ext(float x) {
+  return __builtin_splatvector(x, __rvv_float64m1_t);
+  // CHECK-LABEL: @splat_flt_ext
+  // CHECK: fpext <vscale x {{[0-9]*}} x float> %{{.*}} to <vscale x {{[0-9]*}} x double>
+}
+
+__rvv_int64m1_t splat_flt_tosi(float x) {
+  return __builtin_splatvector(x, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_flt_tosi
+  // CHECK: fptosi <vscale x {{[0-9]*}} x float> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__rvv_uint64m1_t splat_flt_toui(float x) {
+  return __builtin_splatvector(x, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_flt_toui
+  // CHECK: fptoui <vscale x {{[0-9]*}} x float> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__rvv_uint64m1_t splat_fltd_toui(double x) {
+  return __builtin_splatvector(x, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_fltd_toui
+  // CHECK: fptoui <vscale x {{[0-9]*}} x double> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__rvv_uint64m1_t splat_int_zext(unsigned short x) {
+  return __builtin_splatvector(x, __rvv_uint64m1_t);
+  // CHECK-LABEL: @splat_int_zext
+  // CHECK: zext <vscale x {{[0-9]*}} x i16> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__rvv_int64m1_t splat_int_sext(short x) {
+  return __builtin_splatvector(x, __rvv_int64m1_t);
+  // CHECK-LABEL: @splat_int_sext
+  // CHECK: sext <vscale x {{[0-9]*}} x i16> %{{.*}} to <vscale x {{[0-9]*}} x i64>
+}
+
+__rvv_float32m1_t splat_int_tofp(short x) {
+  return __builtin_splatvector(x, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_int_tofp
+  // CHECK: sitofp <vscale x {{[0-9]*}} x i16> %{{.*}} to <vscale x {{[0-9]*}} x float>
+}
+
+__rvv_float32m1_t splat_uint_tofp(unsigned short x) {
+  return __builtin_splatvector(x, __rvv_float32m1_t);
+  // CHECK-LABEL: @splat_uint_tofp
+  // CHECK: uitofp <vscale x {{[0-9]*}} x i16> %{{.*}} to <vscale x {{[0-9]*}} x float>
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+template<typename T>
+T splat_int_toT(long x) {
+  return __builtin_splatvector(x, T);
+}
+
+extern "C" {
+  __rvv_float64m1_t splat_int_toT_fp(long x) {
+    // CHECK-LABEL: @splat_int_toT_fp
+    // CHECK: sitofp <vscale x {{[0-9]*}} x i64> %{{.*}} to <vscale x {{[0-9]*}} x double>
+    return splat_int_toT<__rvv_float64m1_t>(x);
+  }
+}
+#else
+__rvv_float64m1_t splat_int_toT_fp(long x) {
+  return __builtin_splatvector(x, __rvv_float64m1_t);
+}
+#endif
diff --git a/clang/test/CodeGen/splatvector-template.cpp b/clang/test/CodeGen/splatvector-template.cpp
new file mode 100644
index 0000000000000..e4c64b2045e13
--- /dev/null
+++ b/clang/test/CodeGen/splatvector-template.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm %s -o - | FileCheck %s
+
+template <typename T, auto N>
+using simd = T [[clang::ext_vector_type(N)]];
+
+template <typename T, auto N>
+constexpr static simd<T, N> splat(T v) {
+  return __builtin_splatvector(v, simd<T, N>);
+  // CHECK-LABEL: internal
+  // CHECK: store [[TYPE:.*]] %v, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load [[TYPE]], ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <[[SIZE:[0-9]*]] x [[TYPE]]> poison, [[TYPE]] %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <[[SIZE]] x [[TYPE]]> %[[INSERT]], <[[SIZE]] x [[TYPE]]> poison, <[[SIZE]] x [[TYPE]]> zeroinitializer
+  // CHECK: ret <[[SIZE]] x [[TYPE]]> %[[SPLAT]]
+}
+
+const auto vi32x8 = splat<int, 8U>(123);
diff --git a/clang/test/CodeGen/splatvector.c b/clang/test/CodeGen/splatvector.c
new file mode 100644
index 0000000000000..02517d38b87da
--- /dev/null
+++ b/clang/test/CodeGen/splatvector.c
@@ -0,0 +1,524 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -target-cpu corei7-avx -emit-llvm -x c++ %s -o - | FileCheck %s
+
+#include <stdbool.h>
+
+typedef double vector8double __attribute__((__vector_size__(64)));
+typedef float  vector8float  __attribute__((__vector_size__(32)));
+typedef bool   vector8bool   __attribute__((__ext_vector_type__(8)));
+typedef long   vector8long   __attribute__((__vector_size__(64)));
+typedef unsigned long   vector8ulong   __attribute__((__vector_size__(64)));
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+vector8bool splat_bool_imm_vector8bool(void) {
+  return __builtin_splatvector(true, vector8bool);
+  // CHECK-LABEL: @splat_bool_imm_vector8bool
+  // CHECK: store <8 x i1> splat (i1 true), ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_int_imm_vector8bool(void) {
+  return __builtin_splatvector(-1, vector8bool);
+  // CHECK-LABEL: @splat_int_imm_vector8bool
+  // CHECK: store <8 x i1> splat (i1 true), ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_uint_imm_vector8bool(void) {
+  return __builtin_splatvector(1U, vector8bool);
+  // CHECK-LABEL: @splat_uint_imm_vector8bool
+  // CHECK: store <8 x i1> splat (i1 true), ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_float_imm_vector8bool(void) {
+  return __builtin_splatvector(1.0f, vector8bool);
+  // CHECK-LABEL: @splat_float_imm_vector8bool
+  // CHECK: store <8 x i1> splat (i1 true), ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_double_imm_vector8bool(void) {
+  return __builtin_splatvector(1.0, vector8bool);
+  // CHECK-LABEL: @splat_double_imm_vector8bool
+  // CHECK: store <8 x i1> splat (i1 true), ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_bool_var_vector8bool(bool x) {
+  return __builtin_splatvector(x, vector8bool);
+  // CHECK-LABEL: @splat_bool_var_vector8bool
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i1> %[[INSERT]], <8 x i1> poison, <8 x i32> zeroinitializer
+  // CHECK: store <8 x i1> %[[SPLAT]], ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_int_var_vector8bool(int x) {
+  return __builtin_splatvector(x, vector8bool);
+  // CHECK-LABEL: @splat_int_var_vector8bool
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = icmp ne <8 x i32> %[[SPLAT]], zeroinitializer
+  // CHECK: store <8 x i1> %[[CONV]], ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_uint_var_vector8bool(unsigned x) {
+  return __builtin_splatvector(x, vector8bool);
+  // CHECK-LABEL: @splat_uint_var_vector8bool
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = icmp ne <8 x i32> %[[SPLAT]], zeroinitializer
+  // CHECK: store <8 x i1> %[[CONV]], ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_float_var_vector8bool(float x) {
+  return __builtin_splatvector(x, vector8bool);
+  // CHECK-LABEL: @splat_float_var_vector8bool
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x float> %[[INSERT]], <8 x float> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fcmp une <8 x float> %[[SPLAT]], zeroinitializer
+  // CHECK: store <8 x i1> %[[CONV]], ptr %[[RETPTR:.*]]
+}
+
+vector8bool splat_double_var_vector8bool(double x) {
+  return __builtin_splatvector(x, vector8bool);
+  // CHECK-LABEL: @splat_double_var_vector8bool
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x double> %[[INSERT]], <8 x double> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fcmp une <8 x double> %[[SPLAT]], zeroinitializer
+  // CHECK: store <8 x i1> %[[CONV]], ptr %[[RETPTR:.*]]
+}
+
+vector8long splat_bool_imm_vector8long(void) {
+  return __builtin_splatvector(true, vector8long);
+  // CHECK-LABEL: @splat_bool_imm_vector8long
+  // CHECK: ret <8 x i64> splat (i64 1)
+}
+
+vector8long splat_int_imm_vector8long(void) {
+  return __builtin_splatvector(-1, vector8long);
+  // CHECK-LABEL: @splat_int_imm_vector8long
+  // CHECK: ret <8 x i64> splat (i64 -1)
+}
+
+vector8long splat_uint_imm_vector8long(void) {
+  return __builtin_splatvector(1U, vector8long);
+  // CHECK-LABEL: @splat_uint_imm_vector8long
+  // CHECK: ret <8 x i64> splat (i64 1)
+}
+
+vector8long splat_float_imm_vector8long(void) {
+  return __builtin_splatvector(1.0f, vector8long);
+  // CHECK-LABEL: @splat_float_imm_vector8long
+  // CHECK: ret <8 x i64> splat (i64 1)
+}
+
+vector8long splat_double_imm_vector8long(void) {
+  return __builtin_splatvector(1.0, vector8long);
+  // CHECK-LABEL: @splat_double_imm_vector8long
+  // CHECK: ret <8 x i64> splat (i64 1)
+}
+
+vector8long splat_bool_var_vector8long(bool x) {
+  return __builtin_splatvector(x, vector8long);
+  // CHECK-LABEL: @splat_bool_var_vector8long
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i1> %[[INSERT]], <8 x i1> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <8 x i1> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8long splat_int_var_vector8long(int x) {
+  return __builtin_splatvector(x, vector8long);
+  // CHECK-LABEL: @splat_int_var_vector8long
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sext <8 x i32> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8long splat_uint_var_vector8long(unsigned x) {
+  return __builtin_splatvector(x, vector8long);
+  // CHECK-LABEL: @splat_uint_var_vector8long
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <8 x i32> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8long splat_float_var_vector8long(float x) {
+  return __builtin_splatvector(x, vector8long);
+  // CHECK-LABEL: @splat_float_var_vector8long
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x float> %[[INSERT]], <8 x float> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptosi <8 x float> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8long splat_double_var_vector8long(double x) {
+  return __builtin_splatvector(x, vector8long);
+  // CHECK-LABEL: @splat_double_var_vector8long
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x double> %[[INSERT]], <8 x double> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptosi <8 x double> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8ulong splat_bool_imm_vector8ulong(void) {
+  return __builtin_splatvector(true, vector8ulong);
+  // CHECK-LABEL: @splat_bool_imm_vector8ulong
+  // CHECK: ret <8 x i64> splat (i64 1)
+}
+
+vector8ulong splat_int_imm_vector8ulong(void) {
+  return __builtin_splatvector(-1, vector8ulong);
+  // CHECK-LABEL: @splat_int_imm_vector8ulong
+  // CHECK: ret <8 x i64> splat (i64 -1)
+}
+
+vector8ulong splat_uint_imm_vector8ulong(void) {
+  return __builtin_splatvector(1U, vector8ulong);
+  // CHECK-LABEL: @splat_uint_imm_vector8ulong
+  // CHECK: ret <8 x i64> splat (i64 1)
+}
+
+vector8ulong splat_float_imm_vector8ulong(void) {
+  return __builtin_splatvector(1.0f, vector8ulong);
+  // CHECK-LABEL: @splat_float_imm_vector8ulong
+  // CHECK: ret <8 x i64> splat (i64 1)
+}
+
+vector8ulong splat_double_imm_vector8ulong(void) {
+  return __builtin_splatvector(1.0, vector8ulong);
+  // CHECK-LABEL: @splat_double_imm_vector8ulong
+  // CHECK: ret <8 x i64> splat (i64 1)
+}
+
+vector8ulong splat_bool_var_vector8ulong(bool x) {
+  return __builtin_splatvector(x, vector8ulong);
+  // CHECK-LABEL: @splat_bool_var_vector8ulong
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i1> %[[INSERT]], <8 x i1> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <8 x i1> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8ulong splat_int_var_vector8ulong(int x) {
+  return __builtin_splatvector(x, vector8ulong);
+  // CHECK-LABEL: @splat_int_var_vector8ulong
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sext <8 x i32> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8ulong splat_uint_var_vector8ulong(unsigned x) {
+  return __builtin_splatvector(x, vector8ulong);
+  // CHECK-LABEL: @splat_uint_var_vector8ulong
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = zext <8 x i32> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8ulong splat_float_var_vector8ulong(float x) {
+  return __builtin_splatvector(x, vector8ulong);
+  // CHECK-LABEL: @splat_float_var_vector8ulong
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x float> %[[INSERT]], <8 x float> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptoui <8 x float> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8ulong splat_double_var_vector8ulong(double x) {
+  return __builtin_splatvector(x, vector8ulong);
+  // CHECK-LABEL: @splat_double_var_vector8ulong
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x double> %[[INSERT]], <8 x double> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptoui <8 x double> %[[SPLAT]] to <8 x i64>
+  // CHECK: ret <8 x i64> %[[CONV]]
+}
+
+vector8float splat_bool_imm_vector8float(void) {
+  return __builtin_splatvector(true, vector8float);
+  // CHECK-LABEL: @splat_bool_imm_vector8float
+  // CHECK: ret <8 x float> splat (float 1.000000e+00)
+}
+
+vector8float splat_int_imm_vector8float(void) {
+  return __builtin_splatvector(-1, vector8float);
+  // CHECK-LABEL: @splat_int_imm_vector8float
+  // CHECK: ret <8 x float> splat (float -1.000000e+00)
+}
+
+vector8float splat_uint_imm_vector8float(void) {
+  return __builtin_splatvector(1U, vector8float);
+  // CHECK-LABEL: @splat_uint_imm_vector8float
+  // CHECK: ret <8 x float> splat (float 1.000000e+00)
+}
+
+vector8float splat_float_imm_vector8float(void) {
+  return __builtin_splatvector(1.0f, vector8float);
+  // CHECK-LABEL: @splat_float_imm_vector8float
+  // CHECK: ret <8 x float> splat (float 1.000000e+00)
+}
+
+vector8float splat_double_imm_vector8float(void) {
+  return __builtin_splatvector(1.0, vector8float);
+  // CHECK-LABEL: @splat_double_imm_vector8float
+  // CHECK: ret <8 x float> splat (float 1.000000e+00)
+}
+
+vector8float splat_bool_var_vector8float(bool x) {
+  return __builtin_splatvector(x, vector8float);
+  // CHECK-LABEL: @splat_bool_var_vector8float
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i1> %[[INSERT]], <8 x i1> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <8 x i1> %[[SPLAT]] to <8 x float>
+  // CHECK: ret <8 x float> %[[CONV]]
+}
+
+vector8float splat_int_var_vector8float(int x) {
+  return __builtin_splatvector(x, vector8float);
+  // CHECK-LABEL: @splat_int_var_vector8float
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sitofp <8 x i32> %[[SPLAT]] to <8 x float>
+  // CHECK: ret <8 x float> %[[CONV]]
+}
+
+vector8float splat_uint_var_vector8float(unsigned x) {
+  return __builtin_splatvector(x, vector8float);
+  // CHECK-LABEL: @splat_uint_var_vector8float
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <8 x i32> %[[SPLAT]] to <8 x float>
+  // CHECK: ret <8 x float> %[[CONV]]
+}
+
+vector8float splat_float_var_vector8float(float x) {
+  return __builtin_splatvector(x, vector8float);
+  // CHECK-LABEL: @splat_float_var_vector8float
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x float> %[[INSERT]], <8 x float> poison, <8 x i32> zeroinitializer
+  // CHECK: ret <8 x float> %[[SPLAT]]
+}
+
+vector8float splat_double_var_vector8float(double x) {
+  return __builtin_splatvector(x, vector8float);
+  // CHECK-LABEL: @splat_double_var_vector8float
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x double> %[[INSERT]], <8 x double> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fptrunc <8 x double> %[[SPLAT]] to <8 x float>
+  // CHECK: ret <8 x float> %[[CONV]]
+}
+
+vector8double splat_bool_imm_vector8double(void) {
+  return __builtin_splatvector(true, vector8double);
+  // CHECK-LABEL: @splat_bool_imm_vector8double
+  // CHECK: ret <8 x double> splat (double 1.000000e+00)
+}
+
+vector8double splat_int_imm_vector8double(void) {
+  return __builtin_splatvector(-1, vector8double);
+  // CHECK-LABEL: @splat_int_imm_vector8double
+  // CHECK: ret <8 x double> splat (double -1.000000e+00)
+}
+
+vector8double splat_uint_imm_vector8double(void) {
+  return __builtin_splatvector(1U, vector8double);
+  // CHECK-LABEL: @splat_uint_imm_vector8double
+  // CHECK: ret <8 x double> splat (double 1.000000e+00)
+}
+
+vector8double splat_float_imm_vector8double(void) {
+  return __builtin_splatvector(1.0f, vector8double);
+  // CHECK-LABEL: @splat_float_imm_vector8double
+  // CHECK: ret <8 x double> splat (double 1.000000e+00)
+}
+
+vector8double splat_double_imm_vector8double(void) {
+  return __builtin_splatvector(1.0, vector8double);
+  // CHECK-LABEL: @splat_double_imm_vector8double
+  // CHECK: ret <8 x double> splat (double 1.000000e+00)
+}
+
+vector8double splat_bool_var_vector8double(bool x) {
+  return __builtin_splatvector(x, vector8double);
+  // CHECK-LABEL: @splat_bool_var_vector8double
+  // CHECK: %[[STOREDV:.*]] = zext i1 %x to i8
+  // CHECK: store i8 %[[STOREDV]], ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i8, ptr %[[WHERE]]
+  // CHECK: %[[WHAT_I1:.*]] = icmp ne i8 %[[WHAT]], 0
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i1> poison, i1 %[[WHAT_I1]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i1> %[[INSERT]], <8 x i1> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <8 x i1> %[[SPLAT]] to <8 x double>
+  // CHECK: ret <8 x double> %[[CONV]]
+}
+
+vector8double splat_int_var_vector8double(int x) {
+  return __builtin_splatvector(x, vector8double);
+  // CHECK-LABEL: @splat_int_var_vector8double
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = sitofp <8 x i32> %[[SPLAT]] to <8 x double>
+  // CHECK: ret <8 x double> %[[CONV]]
+}
+
+vector8double splat_uint_var_vector8double(unsigned x) {
+  return __builtin_splatvector(x, vector8double);
+  // CHECK-LABEL: @splat_uint_var_vector8double
+  // CHECK: store i32 %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load i32, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x i32> poison, i32 %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x i32> %[[INSERT]], <8 x i32> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = uitofp <8 x i32> %[[SPLAT]] to <8 x double>
+  // CHECK: ret <8 x double> %[[CONV]]
+}
+
+vector8double splat_float_var_vector8double(float x) {
+  return __builtin_splatvector(x, vector8double);
+  // CHECK-LABEL: @splat_float_var_vector8double
+  // CHECK: store float %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load float, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x float> poison, float %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x float> %[[INSERT]], <8 x float> poison, <8 x i32> zeroinitializer
+  // CHECK: %[[CONV:.*]] = fpext <8 x float> %[[SPLAT]] to <8 x double>
+  // CHECK: ret <8 x double> %[[CONV]]
+}
+
+vector8double splat_double_var_vector8double(double x) {
+  return __builtin_splatvector(x, vector8double);
+  // CHECK-LABEL: @splat_double_var_vector8double
+  // CHECK: store double %x, ptr %[[WHERE:.*]]
+  // CHECK: %[[WHAT:.*]] = load double, ptr %[[WHERE]]
+  // CHECK: %[[INSERT:.*]] = insertelement <8 x double> poison, double %[[WHAT]], i64 0
+  // CHECK: %[[SPLAT:.*]] = shufflevector <8 x double> %[[INSERT]], <8 x double> poison, <8 x i32> zeroinitializer
+  // CHECK: ret <8 x double> %[[SPLAT]]
+}
+
+vector8float splat_flt_trunc(double x) {
+  return __builtin_splatvector(x, vector8float);
+  // CHECK-LABEL: @splat_flt_trunc
+  // CHECK: fptrunc <8 x double> %{{.*}} to <8 x float>
+}
+
+vector8double splat_flt_ext(float x) {
+  return __builtin_splatvector(x, vector8double);
+  // CHECK-LABEL: @splat_flt_ext
+  // CHECK: fpext <8 x float> %{{.*}} to <8 x double>
+}
+
+vector8long splat_flt_tosi(float x) {
+  return __builtin_splatvector(x, vector8long);
+  // CHECK-LABEL: @splat_flt_tosi
+  // CHECK: fptosi <8 x float> %{{.*}} to <8 x i64>
+}
+
+vector8ulong splat_flt_toui(float x) {
+  return __builtin_splatvector(x, vector8ulong);
+  // CHECK-LABEL: @splat_flt_toui
+  // CHECK: fptoui <8 x float> %{{.*}} to <8 x i64>
+}
+
+vector8ulong splat_fltd_toui(double x) {
+  return __builtin_splatvector(x, vector8ulong);
+  // CHECK-LABEL: @splat_fltd_toui
+  // CHECK: fptoui <8 x double> %{{.*}} to <8 x i64>
+}
+
+vector8ulong splat_int_zext(unsigned short x) {
+  return __builtin_splatvector(x, vector8ulong);
+  // CHECK-LABEL: @splat_int_zext
+  // CHECK: zext <8 x i16> %{{.*}} to <8 x i64>
+}
+
+vector8long splat_int_sext(short x) {
+  return __builtin_splatvector(x, vector8long);
+  // CHECK-LABEL: @splat_int_sext
+  // CHECK: sext <8 x i16> %{{.*}} to <8 x i64>
+}
+
+vector8float splat_int_tofp(short x) {
+  return __builtin_splatvector(x, vector8float);
+  // CHECK-LABEL: @splat_int_tofp
+  // CHECK: sitofp <8 x i16> %{{.*}} to <8 x float>
+}
+
+vector8float splat_uint_tofp(unsigned short x) {
+  return __builtin_splatvector(x, vector8float);
+  // CHECK-LABEL: @splat_uint_tofp
+  // CHECK: uitofp <8 x i16> %{{.*}} to <8 x float>
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+template<typename T>
+T splat_int_toT(long x) {
+  return __builtin_splatvector(x, T);
+}
+
+extern "C" {
+  vector8double splat_int_toT_fp(long x) {
+    // CHECK-LABEL: @splat_int_toT_fp
+    // CHECK: sitofp <8 x i64> %{{.*}} to <8 x double>
+    return splat_int_toT<vector8double>(x);
+  }
+}
+#else
+vector8double splat_int_toT_fp(long x) {
+  return __builtin_splatvector(x, vector8double);
+}
+#endif
diff --git a/clang/test/PCH/exprs.h b/clang/test/PCH/exprs.h
index d6735a727a538..a0d31815b578b 100644
--- a/clang/test/PCH/exprs.h
+++ b/clang/test/PCH/exprs.h
@@ -102,6 +102,10 @@ typedef typeof(__builtin_choose_expr(17 > 19, d0, 1)) choose_expr;
 // ShuffleVectorExpr
 typedef typeof(__builtin_shufflevector(vec2, vec2b, 2, 1)) shuffle_expr;
 
+// SplatVectorExpr
+typedef __attribute__(( ext_vector_type(2) )) float float2;
+typedef typeof(__builtin_splatvector(d0, float2)) splat_expr;
+
 // ConvertVectorExpr
 typedef __attribute__(( ext_vector_type(2) )) float float2;
 typedef typeof(__builtin_convertvector(vec2, float2)) convert_expr;
diff --git a/clang/test/Preprocessor/feature_tests.c b/clang/test/Preprocessor/feature_tests.c
index e8aecfb82cb3b..82e19bf42809d 100644
--- a/clang/test/Preprocessor/feature_tests.c
+++ b/clang/test/Preprocessor/feature_tests.c
@@ -13,6 +13,7 @@
 
 #if  !__has_builtin(__builtin_huge_val) || \
      !__has_builtin(__builtin_shufflevector) || \
+     !__has_builtin(__builtin_splatvector) || \
      !__has_builtin(__builtin_convertvector) || \
      !__has_builtin(__builtin_trap) || \
      !__has_builtin(__c11_atomic_init) || \
diff --git a/clang/test/Preprocessor/feature_tests.cpp b/clang/test/Preprocessor/feature_tests.cpp
index 029f446113af4..5e78130bdba13 100644
--- a/clang/test/Preprocessor/feature_tests.cpp
+++ b/clang/test/Preprocessor/feature_tests.cpp
@@ -11,6 +11,7 @@
 
 #if  !__has_builtin(__builtin_huge_val) || \
      !__has_builtin(__builtin_shufflevector) || \
+     !__has_builtin(__builtin_splatvector) || \
      !__has_builtin(__builtin_convertvector) || \
      !__has_builtin(__builtin_trap) || \
      !__has_builtin(__c11_atomic_init) || \
@@ -64,6 +65,10 @@
 #error Clang should have these constexpr builtins
 #endif
 
+#if !__has_constexpr_builtin(__builtin_splatvector)
+#error Clang should have these constexpr builtins
+#endif
+
 #if !__has_constexpr_builtin(__builtin_convertvector)
 #error Clang should have these constexpr builtins
 #endif
diff --git a/clang/test/Sema/splatvector.c b/clang/test/Sema/splatvector.c
new file mode 100644
index 0000000000000..d38d6b6fae82c
--- /dev/null
+++ b/clang/test/Sema/splatvector.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef double vector4double __attribute__((__vector_size__(32)));
+typedef float  vector8float  __attribute__((__vector_size__(32)));
+
+vector8float foo1(vector4double x) {
+  return __builtin_splatvector(x, vector8float);  // expected-error {{first argument to __builtin_splatvector must be a single value}}
+}
+
+float foo2(vector4double x) {
+  return __builtin_splatvector(x, float);  // expected-error {{first argument to __builtin_splatvector must be a single value}}
+}
+
+float foo4(float x) {
+  return __builtin_splatvector(x, float); // expected-error {{second argument to __builtin_splatvector must be of vector type}}
+}
diff --git a/clang/test/Sema/vector-bool-assign.c b/clang/test/Sema/vector-bool-assign.c
index 8f9d7b17a1ecb..5aeefd1509e87 100644
--- a/clang/test/Sema/vector-bool-assign.c
+++ b/clang/test/Sema/vector-bool-assign.c
@@ -16,6 +16,12 @@ v8b integral(v8i v) {
   v8b m4 = __builtin_convertvector(v, __attribute__((ext_vector_type(8))) unsigned long);
   v8b m5 = __builtin_convertvector(v, __attribute__((ext_vector_type(8))) char);
   v8b m6 = __builtin_convertvector(v, __attribute__((ext_vector_type(8))) unsigned char);
+  v8b s1 = __builtin_splatvector(v[0], __attribute__((ext_vector_type(8))) int);
+  v8b s2 = __builtin_splatvector(v[0], __attribute__((ext_vector_type(8))) unsigned);
+  v8b s3 = __builtin_splatvector(v[0], __attribute__((ext_vector_type(8))) long);
+  v8b s4 = __builtin_splatvector(v[0], __attribute__((ext_vector_type(8))) unsigned long);
+  v8b s5 = __builtin_splatvector(v[0], __attribute__((ext_vector_type(8))) char);
+  v8b s6 = __builtin_splatvector(v[0], __attribute__((ext_vector_type(8))) unsigned char);
   foo(v);
   return v;
 }
diff --git a/clang/test/Sema/vector-bool-assign.cpp b/clang/test/Sema/vector-bool-assign.cpp
index 115ec50f6b448..877dcc9037df9 100644
--- a/clang/test/Sema/vector-bool-assign.cpp
+++ b/clang/test/Sema/vector-bool-assign.cpp
@@ -14,6 +14,12 @@ v8b integral(v8i v) {
   v8b m4 = __builtin_convertvector(v, unsigned long [[clang::ext_vector_type(8)]]);
   v8b m5 = __builtin_convertvector(v, char [[clang::ext_vector_type(8)]]);
   v8b m6 = __builtin_convertvector(v, unsigned char [[clang::ext_vector_type(8)]]);
+  v8b s1 = __builtin_splatvector(v[0], int [[clang::ext_vector_type(8)]]);
+  v8b s2 = __builtin_splatvector(v[0], unsigned [[clang::ext_vector_type(8)]]);
+  v8b s3 = __builtin_splatvector(v[0], long [[clang::ext_vector_type(8)]]);
+  v8b s4 = __builtin_splatvector(v[0], unsigned long [[clang::ext_vector_type(8)]]);
+  v8b s5 = __builtin_splatvector(v[0], char [[clang::ext_vector_type(8)]]);
+  v8b s6 = __builtin_splatvector(v[0], unsigned char [[clang::ext_vector_type(8)]]);
   foo(v);
   return v;
 }
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index fb0b3c1502574..0b33a8a925afb 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -336,6 +336,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
   case Stmt::PredefinedExprClass:
   case Stmt::ShuffleVectorExprClass:
   case Stmt::SourceLocExprClass:
+  case Stmt::SplatVectorExprClass:
   case Stmt::ConvertVectorExprClass:
   case Stmt::VAArgExprClass:
   case Stmt::ObjCArrayLiteralClass:
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 503f5da8af90f..e1be4a5d76494 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -460,6 +460,28 @@ TEST_P(ImportExpr, ImportStmtExpr) {
                        hasDescendant(implicitCastExpr()))))))));
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportSplatVectorExpr) {
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+      "typedef double v4double __attribute__((__vector_size__(32)));"
+      "float f;"
+      "void declToImport() { (void)__builtin_splatvector(f, v4double); }",
+      Lang_CXX03, "", Lang_CXX03);
+
+  auto ToResults =
+      match(splatVectorExpr().bind("splat"), To->getASTContext());
+  auto FromResults =
+      match(splatVectorExpr().bind("splat"), From->getASTContext());
+
+  const SplatVectorExpr *FromSplatVectorExpr =
+      selectFirst<SplatVectorExpr>("splat", FromResults);
+  ASSERT_TRUE(FromSplatVectorExpr);
+
+  const SplatVectorExpr *ToSplatVectorExpr =
+      selectFirst<SplatVectorExpr>("splat", ToResults);
+  ASSERT_TRUE(ToSplatVectorExpr);
+}
+
 TEST_P(ImportExpr, ImportConditionalOperator) {
   MatchVerifier<Decl> Verifier;
   testImport("void declToImport() { (void)(true ? 1 : -5); }", Lang_CXX03, "",
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 4190d4703e37d..4f6791a0ef1bf 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1170,6 +1170,16 @@ TEST_P(ASTMatchersTest, ParenListExpr) {
               varDecl(hasInitializer(parenListExpr(has(unaryOperator()))))));
 }
 
+TEST_P(ASTMatchersTest, SplatVectorExpr) {
+  EXPECT_TRUE(matches(
+      "typedef double vector4double __attribute__((__vector_size__(32)));"
+      "float f;"
+      "void foo() { (void)__builtin_splatvector(f, vector4double); }",
+      splatVectorExpr()));
+  EXPECT_TRUE(notMatches("void foo() { (void)__builtin_choose_expr(1, 2, 3); }",
+                         splatVectorExpr()));
+}
+
 TEST_P(ASTMatchersTest, StmtExpr) {
   EXPECT_TRUE(matches("void declToImport() { int C = ({int X=4; X;}); }",
                       varDecl(hasInitializer(stmtExpr()))));



More information about the cfe-commits mailing list