https://github.com/perry-ca created 
https://github.com/llvm/llvm-project/pull/202397

On z/OS, the user has a choice between two different va_list formats.  
1. (default) uses the __builtin_zos_va_list typedef for va_list, being added in 
this change
2. (-D_VARARG_EXT_) uses __builtin_va_list typedef for va_list.

The __builtin_zos_va_list type is `char * [2]`. 

This PR adds this type along with the __builtin_zos_va_start(), 
__builtin_zos_va_end() & __builtin_zos_va_copy() functions to go with it.

>From 70f8ccec5ba4358e7fc6a29f02fb86e593f71be1 Mon Sep 17 00:00:00 2001
From: Sean Perry <[email protected]>
Date: Fri, 5 Jun 2026 17:45:13 -0400
Subject: [PATCH 1/4] Implement zos va_list

---
 clang/include/clang/AST/ASTContext.h      | 14 ++++++++
 clang/include/clang/AST/DeclID.h          |  3 ++
 clang/include/clang/AST/Expr.h            | 21 ++++++++----
 clang/include/clang/Basic/Builtins.td     | 19 ++++++++++
 clang/include/clang/Basic/TargetInfo.h    |  7 ++++
 clang/lib/AST/ASTContext.cpp              | 16 +++++++++
 clang/lib/AST/ASTImporter.cpp             |  6 ++--
 clang/lib/Basic/TargetInfo.cpp            |  1 +
 clang/lib/Basic/Targets/SystemZ.h         |  4 +++
 clang/lib/CodeGen/ABIInfo.cpp             |  5 +++
 clang/lib/CodeGen/ABIInfo.h               |  6 ++++
 clang/lib/CodeGen/CGBuiltin.cpp           | 30 ++++++++++++++++
 clang/lib/CodeGen/CGCall.cpp              |  8 +++--
 clang/lib/CodeGen/CodeGenFunction.cpp     |  4 +++
 clang/lib/CodeGen/CodeGenFunction.h       |  5 +++
 clang/lib/CodeGen/Targets/SystemZ.cpp     | 42 +++++++++++++++++++++++
 clang/lib/Sema/Sema.cpp                   |  8 +++++
 clang/lib/Sema/SemaChecking.cpp           |  1 +
 clang/lib/Sema/SemaExpr.cpp               | 28 ++++++++++++---
 clang/lib/Serialization/ASTReader.cpp     |  6 ++++
 clang/lib/Serialization/ASTReaderStmt.cpp |  2 +-
 clang/lib/Serialization/ASTWriter.cpp     |  2 ++
 22 files changed, 221 insertions(+), 17 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 54c046f5fab4a..0f196c6de1976 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -442,6 +442,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// The typedef for the predefined \c __builtin_ms_va_list type.
   mutable TypedefDecl *BuiltinMSVaListDecl = nullptr;
 
+  /// The typedef for the predefined \c __builtin_zos_va_list type.
+  mutable TypedefDecl *BuiltinZOSVaListDecl = nullptr;
+
   /// The typedef for the predefined \c id type.
   mutable TypedefDecl *ObjCIdDecl = nullptr;
 
@@ -2523,6 +2526,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
     return MSTypeInfoTagDecl;
   }
 
+  /// Retrieve the C type declaration corresponding to the predefined
+  /// \c __builtin_zos_va_list type.
+  TypedefDecl *getBuiltinZOSVaListDecl() const;
+
+  /// Retrieve the type of the \c __builtin_zos_va_list type.
+  QualType getBuiltinZOSVaListType() const {
+    return getTypedefType(ElaboratedTypeKeyword::None,
+                          /*Qualifier=*/std::nullopt,
+                          getBuiltinZOSVaListDecl());
+  }
+
   /// Return whether a declaration to a builtin is allowed to be
   /// overloaded/redeclared.
   bool canBuiltinBeRedeclared(const FunctionDecl *) const;
diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h
index 8a173e3d96349..b38875afeee84 100644
--- a/clang/include/clang/AST/DeclID.h
+++ b/clang/include/clang/AST/DeclID.h
@@ -80,6 +80,9 @@ enum PredefinedDeclIDs {
   /// The predeclared 'type_info' struct.
   PREDEF_DECL_BUILTIN_MS_TYPE_INFO_TAG_ID,
 
+  /// The internal '__builtin_zos_va_list' typedef.
+  PREDEF_DECL_BUILTIN_ZOS_VA_LIST_ID,
+
 #define BuiltinTemplate(BTName) PREDEF_DECL##BTName##_ID,
 #include "clang/Basic/BuiltinTemplates.inc"
 
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index b91bf4a5375fb..dd96f7f1bf02e 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -4958,28 +4958,37 @@ class GNUNullExpr : public Expr {
 
 /// Represents a call to the builtin function \c __builtin_va_arg.
 class VAArgExpr : public Expr {
+public:
+  enum VarArgKind { VA_Std = 0, VA_MS, VA_ZOS };
+
+private:
   Stmt *Val;
-  llvm::PointerIntPair<TypeSourceInfo *, 1, bool> TInfo;
+  llvm::PointerIntPair<TypeSourceInfo *, 2, VarArgKind> TInfo;
   SourceLocation BuiltinLoc, RParenLoc;
 public:
   VAArgExpr(SourceLocation BLoc, Expr *e, TypeSourceInfo *TInfo,
-            SourceLocation RPLoc, QualType t, bool IsMS)
+            SourceLocation RPLoc, QualType t, VarArgKind VaKind)
       : Expr(VAArgExprClass, t, VK_PRValue, OK_Ordinary), Val(e),
-        TInfo(TInfo, IsMS), BuiltinLoc(BLoc), RParenLoc(RPLoc) {
+        TInfo(TInfo, VaKind), BuiltinLoc(BLoc), RParenLoc(RPLoc) {
     setDependence(computeDependence(this));
   }
 
   /// Create an empty __builtin_va_arg expression.
   explicit VAArgExpr(EmptyShell Empty)
-      : Expr(VAArgExprClass, Empty), Val(nullptr), TInfo(nullptr, false) {}
+      : Expr(VAArgExprClass, Empty), Val(nullptr), TInfo(nullptr, VA_Std) {}
 
   const Expr *getSubExpr() const { return cast<Expr>(Val); }
   Expr *getSubExpr() { return cast<Expr>(Val); }
   void setSubExpr(Expr *E) { Val = E; }
 
+  VarArgKind getVarargABI() { return TInfo.getInt(); }
+  void setVarargABI(int Kind) { TInfo.setInt(static_cast<VarArgKind>(Kind)); }
+
   /// Returns whether this is really a Win64 ABI va_arg expression.
-  bool isMicrosoftABI() const { return TInfo.getInt(); }
-  void setIsMicrosoftABI(bool IsMS) { TInfo.setInt(IsMS); }
+  bool isMicrosoftABI() const { return TInfo.getInt() == VA_MS; }
+
+  /// Returns whether this is really a z/OS ABI va_arg expression.
+  bool isZOSABI() const { return TInfo.getInt() == VA_ZOS; }
 
   TypeSourceInfo *getWrittenTypeInfo() const { return TInfo.getPointer(); }
   void setWrittenTypeInfo(TypeSourceInfo *TI) { TInfo.setPointer(TI); }
diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 8d2a824ef5610..8f62f1e995f32 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5809,6 +5809,25 @@ def MSVaCopy : Builtin {
   let Prototype = "void(char*&, char*&)";
 }
 
+// z/OS-compatible va_list functions.
+def ZOSVaStart : Builtin {
+  let Spellings = ["__builtin_zos_va_start"];
+  let Attributes = [NoThrow, CustomTypeChecking];
+  let Prototype = "void(char**, ...)";
+}
+
+def ZOSVaEnd : Builtin {
+  let Spellings = ["__builtin_zos_va_end"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(char**)";
+}
+
+def ZOSVaCopy : Builtin {
+  let Spellings = ["__builtin_zos_va_copy"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(char**, char**)";
+}
+
 // Arithmetic Fence: to prevent FP reordering and reassociation optimizations
 // FIXME: Should this just be a Builtin?
 def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
diff --git a/clang/include/clang/Basic/TargetInfo.h 
b/clang/include/clang/Basic/TargetInfo.h
index cc226403877e2..4f30408b2f0ef 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -272,6 +272,9 @@ class TargetInfo : public TransferrableTargetInfo,
   LLVM_PREFERRED_TYPE(bool)
   unsigned HasBuiltinMSVaList : 1;
 
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned HasBuiltinZOSVaList : 1;
+
   LLVM_PREFERRED_TYPE(bool)
   unsigned HasAArch64ACLETypes : 1;
 
@@ -1072,6 +1075,10 @@ class TargetInfo : public TransferrableTargetInfo,
   /// available on this target.
   bool hasBuiltinMSVaList() const { return HasBuiltinMSVaList; }
 
+  /// Returns whether or not type \c __builtin_zos_va_list type is
+  /// available on this target.
+  bool hasBuiltinZOSVaList() const { return HasBuiltinZOSVaList; }
+
   /// Returns whether or not the AArch64 ACLE built-in types are
   /// available on this target.
   bool hasAArch64ACLETypes() const { return HasAArch64ACLETypes; }
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index d7e2a0f9c4803..e3c21b48e90bd 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -9995,6 +9995,15 @@ static TypedefDecl *CreateMSVaListDecl(const ASTContext 
*Context) {
   return CreateCharPtrNamedVaListDecl(Context, "__builtin_ms_va_list");
 }
 
+static TypedefDecl *CreateZOSVaListDecl(const ASTContext *Context) {
+  // typedef char *__builtin_va_list[2];
+  llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 2);
+  QualType T = Context->getPointerType(Context->CharTy);
+  QualType ArrayType = Context->getConstantArrayType(
+      T, Size, nullptr, ArraySizeModifier::Normal, 0);
+  return Context->buildImplicitTypedef(ArrayType, "__builtin_zos_va_list");
+}
+
 static TypedefDecl *CreateCharPtrBuiltinVaListDecl(const ASTContext *Context) {
   return CreateCharPtrNamedVaListDecl(Context, "__builtin_va_list");
 }
@@ -10422,6 +10431,13 @@ TypedefDecl *ASTContext::getBuiltinMSVaListDecl() 
const {
   return BuiltinMSVaListDecl;
 }
 
+TypedefDecl *ASTContext::getBuiltinZOSVaListDecl() const {
+  if (!BuiltinZOSVaListDecl)
+    BuiltinZOSVaListDecl = CreateZOSVaListDecl(this);
+
+  return BuiltinZOSVaListDecl;
+}
+
 bool ASTContext::canBuiltinBeRedeclared(const FunctionDecl *FD) const {
   // Allow redecl custom type checking builtin for HLSL.
   if (LangOpts.HLSL && FD->getBuiltinID() != Builtin::NotBuiltin &&
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index f8c641789bd10..221b2bb401fa0 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -7625,9 +7625,9 @@ ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr 
*E) {
   if (Err)
     return std::move(Err);
 
-  return new (Importer.getToContext()) VAArgExpr(
-      ToBuiltinLoc, ToSubExpr, ToWrittenTypeInfo, ToRParenLoc, ToType,
-      E->isMicrosoftABI());
+  return new (Importer.getToContext())
+      VAArgExpr(ToBuiltinLoc, ToSubExpr, ToWrittenTypeInfo, ToRParenLoc, 
ToType,
+                E->getVarargABI());
 }
 
 ExpectedStmt ASTNodeImporter::VisitChooseExpr(ChooseExpr *E) {
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 854d23cadaea2..4c48a97b45951 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -164,6 +164,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
   SSERegParmMax = 0;
   HasAlignMac68kSupport = false;
   HasBuiltinMSVaList = false;
+  HasBuiltinZOSVaList = false;
   HasAArch64ACLETypes = false;
   HasRISCVVTypes = false;
   AllowAMDGPUUnsafeFPAtomics = false;
diff --git a/clang/lib/Basic/Targets/SystemZ.h 
b/clang/lib/Basic/Targets/SystemZ.h
index 00f7d7a055b24..74ad7d722a43f 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -83,6 +83,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public 
TargetInfo {
         AddrSpaceMap = &ZOSAddressMap;
       }
       TLSSupported = false;
+      HasBuiltinZOSVaList = true;
+
       // All vector types are default aligned on an 8-byte boundary, even if 
the
       // vector facility is not available. That is different from Linux.
       MaxVectorAlign = 64;
@@ -166,6 +168,8 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public 
TargetInfo {
   }
 
   BuiltinVaListKind getBuiltinVaListKind() const override {
+    if (getTriple().isOSzOS())
+      return TargetInfo::CharPtrBuiltinVaList;
     return TargetInfo::SystemZBuiltinVaList;
   }
 
diff --git a/clang/lib/CodeGen/ABIInfo.cpp b/clang/lib/CodeGen/ABIInfo.cpp
index 16005890a0708..eede3b54d7b4a 100644
--- a/clang/lib/CodeGen/ABIInfo.cpp
+++ b/clang/lib/CodeGen/ABIInfo.cpp
@@ -44,6 +44,11 @@ RValue ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address 
VAListAddr,
   return RValue::getIgnored();
 }
 
+RValue ABIInfo::EmitZOSVAArg(CodeGenFunction &CGF, Address VAListAddr,
+                             QualType Ty, AggValueSlot Slot) const {
+  return RValue::getIgnored();
+}
+
 bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
   return false;
 }
diff --git a/clang/lib/CodeGen/ABIInfo.h b/clang/lib/CodeGen/ABIInfo.h
index 576cf8f742446..4563154d50960 100644
--- a/clang/lib/CodeGen/ABIInfo.h
+++ b/clang/lib/CodeGen/ABIInfo.h
@@ -91,6 +91,12 @@ class ABIInfo {
                              CodeGen::Address VAListAddr, QualType Ty,
                              AggValueSlot Slot) const;
 
+  /// Emit the target dependent code to load a value of
+  /// \arg Ty from the \c __builtin_zos_va_list pointed to by \arg VAListAddr.
+  virtual RValue EmitZOSVAArg(CodeGen::CodeGenFunction &CGF,
+                              CodeGen::Address VAListAddr, QualType Ty,
+                              AggValueSlot Slot) const;
+
   virtual bool isHomogeneousAggregateBaseType(QualType Ty) const;
 
   virtual bool isHomogeneousAggregateSmallEnough(const Type *Base,
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 0cb5f95049789..4083c1f34e413 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -6976,6 +6976,36 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl 
GD, unsigned BuiltinID,
     return RValue::get(Builder.CreateStore(ArgPtr, DestAddr));
   }
 
+  case Builtin::BI__builtin_zos_va_start:
+  case Builtin::BI__builtin_zos_va_end: {
+    // The va_list is an array with 2 elements, called curr and next.
+    // Element curr is set to 0. For builtin_zos_va_start, next is initialized
+    // with a call to @llvm.va_start. Otherwise, next is passed to 
@llvm.va_end.
+    Address VAList = EmitZOSVAListRef(E->getArg(0));
+    llvm::Type *VAListTy = ConvertType(getContext().getBuiltinZOSVaListType());
+    VAList = VAList.withElementType(VAListTy);
+    Address Curr = Builder.CreateConstArrayGEP(VAList, 0, "curr");
+    Value *Zero = llvm::Constant::getNullValue(VoidPtrTy);
+    Builder.CreateStore(Zero, Curr);
+    Address Next = Builder.CreateConstArrayGEP(VAList, 1, "next");
+    return RValue::get(
+        EmitVAStartEnd(Next.emitRawPointer(*this),
+                       BuiltinID == Builtin::BI__builtin_zos_va_start));
+  }
+  case Builtin::BI__builtin_zos_va_copy: {
+    // Lower this manually because later  can't reliably determine the type.
+    Address Dest = EmitZOSVAListRef(E->getArg(0));
+    Address Src = EmitZOSVAListRef(E->getArg(1));
+    // Value *SizeVal = llvm::ConstantInt::get(Int64Ty, 2 *
+    // getPointerSize().getQuantity());
+    llvm::Type *VAListTy = ConvertType(getContext().getBuiltinZOSVaListType());
+    uint64_t SizeBytes =
+        CGM.getDataLayout().getTypeAllocSize(VAListTy).getFixedValue();
+    Value *SizeVal = llvm::ConstantInt::get(Int64Ty, SizeBytes);
+    Builder.CreateMemCpy(Dest, Src, SizeVal, false);
+    return RValue::get(Dest.emitRawPointer(*this));
+  }
+
   case Builtin::BI__builtin_get_device_side_mangled_name: {
     auto Name = CGM.getCUDARuntime().getDeviceSideName(
         cast<DeclRefExpr>(E->getArg(0)->IgnoreImpCasts())->getDecl());
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 40cc275d40273..d2d6179b0616d 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6584,13 +6584,17 @@ CGCallee 
CGCallee::prepareConcreteCallee(CodeGenFunction &CGF) const {
 
 RValue CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr,
                                   AggValueSlot Slot) {
-  VAListAddr = VE->isMicrosoftABI() ? EmitMSVAListRef(VE->getSubExpr())
-                                    : EmitVAListRef(VE->getSubExpr());
+  VAListAddr = VE->isMicrosoftABI()
+                   ? EmitMSVAListRef(VE->getSubExpr())
+                   : (VE->isZOSABI() ? EmitZOSVAListRef(VE->getSubExpr())
+                                     : EmitVAListRef(VE->getSubExpr()));
   QualType Ty = VE->getType();
   if (Ty->isVariablyModifiedType())
     EmitVariablyModifiedType(Ty);
   if (VE->isMicrosoftABI())
     return CGM.getABIInfo().EmitMSVAArg(*this, VAListAddr, Ty, Slot);
+  if (VE->isZOSABI())
+    return CGM.getABIInfo().EmitZOSVAArg(*this, VAListAddr, Ty, Slot);
   return CGM.getABIInfo().EmitVAArg(*this, VAListAddr, Ty, Slot);
 }
 
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
index b920266b59808..80c5268495fe6 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2700,6 +2700,10 @@ Address CodeGenFunction::EmitMSVAListRef(const Expr *E) {
   return EmitLValue(E).getAddress();
 }
 
+Address CodeGenFunction::EmitZOSVAListRef(const Expr *E) {
+  return EmitPointerWithAlignment(E);
+}
+
 void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
                                               const APValue &Init) {
   assert(Init.hasValue() && "Invalid DeclRefExpr initializer!");
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 6bb9f285ebcfd..ddf00c1860fb0 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3013,6 +3013,11 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// pointer to a char.
   Address EmitMSVAListRef(const Expr *E);
 
+  /// Emit a "reference" to a __builtin_zos_va_list; this is always the
+  /// address of the expression, because a __builtin_zos_va_list is an
+  /// array of pointer to a char.
+  Address EmitZOSVAListRef(const Expr *E);
+
   /// EmitAnyExprToTemp - Similarly to EmitAnyExpr(), however, the result will
   /// always be accessible even if no aggregate location is provided.
   RValue EmitAnyExprToTemp(const Expr *E);
diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp 
b/clang/lib/CodeGen/Targets/SystemZ.cpp
index 5c7485ed0944f..0ea918411509e 100644
--- a/clang/lib/CodeGen/Targets/SystemZ.cpp
+++ b/clang/lib/CodeGen/Targets/SystemZ.cpp
@@ -586,6 +586,9 @@ class ZOSXPLinkABIInfo : public ABIInfo {
 
   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
                    AggValueSlot Slot) const override;
+
+  RValue EmitZOSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
+                      AggValueSlot Slot) const override;
 };
 
 class ZOSXPLinkTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -907,6 +910,45 @@ RValue ZOSXPLinkABIInfo::EmitVAArg(CodeGenFunction &CGF, 
Address VAListAddr,
                           /*allowHigherAlign*/ false, Slot);
 }
 
+RValue ZOSXPLinkABIInfo::EmitZOSVAArg(CodeGenFunction &CGF, Address VAListAddr,
+                                      QualType ArgTy, AggValueSlot Slot) const 
{
+  // Assume that va_list type is correct; should be pointer
+  // to LLVM type: [2 x i8*].
+  llvm::Type *VAListTy =
+      CGF.ConvertType(getContext().getBuiltinZOSVaListType());
+  VAListAddr = VAListAddr.withElementType(VAListTy);
+  Address Curr = CGF.Builder.CreateConstArrayGEP(VAListAddr, 0, 
"va_list.curr");
+  Address Next = CGF.Builder.CreateConstArrayGEP(VAListAddr, 1, 
"va_list.next");
+
+  // Get information about the argument type.
+  auto ArgTyInfo = CGF.getContext().getTypeInfoInChars(ArgTy);
+  CharUnits ArgTySize = ArgTyInfo.Width;
+
+  llvm::Type *Ty = CGF.ConvertTypeForMem(ArgTy);
+
+  // Slot size is the same as the size of a pointer.
+  CharUnits SlotSize = CGF.getPointerSize();
+
+  // Align next and copy to curr.
+  CharUnits PtrAlign = CGF.getPointerAlign();
+  llvm::Value *OldNext = CGF.Builder.CreateLoad(Next, "arg.next");
+  Address Addr = Address(emitRoundPointerUpToAlignment(CGF, OldNext, PtrAlign),
+                         CGF.Int8Ty, PtrAlign);
+  CGF.Builder.CreateStore(Addr.emitRawPointer(CGF), Curr);
+
+  // Advance next and store.
+  Address NextPtr = CGF.Builder.CreateConstInBoundsByteGEP(
+      Addr, ArgTySize.isZero() ? SlotSize : ArgTySize, "arg.next.next");
+  CGF.Builder.CreateStore(NextPtr.emitRawPointer(CGF), Next);
+
+  // Fetch next arg
+  if (ArgTySize < SlotSize && !isAggregateTypeForABI(ArgTy))
+    Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - ArgTySize);
+
+  return CGF.EmitLoadOfAnyValue(
+      CGF.MakeAddrLValue(Addr.withElementType(Ty), ArgTy), Slot);
+}
+
 std::unique_ptr<TargetCodeGenInfo>
 CodeGen::createSystemZTargetCodeGenInfo(CodeGenModule &CGM, bool HasVector,
                                         bool SoftFloatABI) {
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 78fbc9e31842d..ad24957feaae0 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -375,6 +375,8 @@ void Sema::Initialize() {
   // name mangling. And the name mangling uses BuiltinVaListDecl.
   if (Context.getTargetInfo().hasBuiltinMSVaList())
     (void)Context.getBuiltinMSVaListDecl();
+  if (Context.getTargetInfo().hasBuiltinZOSVaList())
+    (void)Context.getBuiltinZOSVaListDecl();
   (void)Context.getBuiltinVaListDecl();
 
   if (SemaConsumer *SC = dyn_cast<SemaConsumer>(&Consumer))
@@ -586,6 +588,12 @@ void Sema::Initialize() {
       PushOnScopeChains(Context.getBuiltinMSVaListDecl(), TUScope);
   }
 
+  if (Context.getTargetInfo().hasBuiltinZOSVaList()) {
+    DeclarationName ZOSVaList = &Context.Idents.get("__builtin_zos_va_list");
+    if (IdResolver.begin(ZOSVaList) == IdResolver.end())
+      PushOnScopeChains(Context.getBuiltinZOSVaListDecl(), TUScope);
+  }
+
   DeclarationName BuiltinVaList = &Context.Idents.get("__builtin_va_list");
   if (IdResolver.begin(BuiltinVaList) == IdResolver.end())
     PushOnScopeChains(Context.getBuiltinVaListDecl(), TUScope);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 8a8c9cc9d2c23..ef4306f1d74c6 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2946,6 +2946,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, 
unsigned BuiltinID,
       return ExprError();
     break;
   case Builtin::BI__builtin_ms_va_start:
+  case Builtin::BI__builtin_zos_va_start:
   case Builtin::BI__builtin_stdarg_start:
   case Builtin::BI__builtin_va_start:
   case Builtin::BI__builtin_c23_va_start:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ad6e7183cb3a4..d34e68ebd4906 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -17203,7 +17203,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation 
BuiltinLoc,
                                 Expr *E, TypeSourceInfo *TInfo,
                                 SourceLocation RPLoc) {
   Expr *OrigExpr = E;
-  bool IsMS = false;
+  VAArgExpr::VarArgKind VAKind = VAArgExpr::VA_Std;
 
   // CUDA device global function does not support varargs.
   if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
@@ -17228,13 +17228,31 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation 
BuiltinLoc,
     if (Context.hasSameType(MSVaListType, E->getType())) {
       if (CheckForModifiableLvalue(E, BuiltinLoc, *this))
         return ExprError();
-      IsMS = true;
+      VAKind = VAArgExpr::VA_MS;
     }
   }
 
   // Get the va_list type
   QualType VaListType = Context.getBuiltinVaListType();
-  if (!IsMS) {
+
+  // It might be a __builtin_zos_va_list!
+  if (!E->isTypeDependent() && Context.getTargetInfo().hasBuiltinZOSVaList()) {
+    // E->getType() can be:
+    //  - va_list: equal to array (char*)[2] (inside function)
+    //  - char **: decayed array (va_list passed as parameter)
+    // We need to check for both cases.
+    QualType ZOSVaListType = Context.getBuiltinZOSVaListType();
+    assert(ZOSVaListType->isArrayType() &&
+           "__builtin_zos_va_list must be an array type");
+    QualType DecayedType = Context.getArrayDecayedType(ZOSVaListType);
+    if (Context.hasSameType(ZOSVaListType, E->getType()) ||
+        Context.hasSameType(DecayedType, E->getType())) {
+      VAKind = VAArgExpr::VA_ZOS;
+      VaListType = ZOSVaListType;
+    }
+  }
+
+  if (VAKind != VAArgExpr::VA_MS) {
     if (VaListType->isArrayType()) {
       // Deal with implicit array decay; for example, on x86-64,
       // va_list is an array, but it's supposed to decay to
@@ -17263,7 +17281,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation 
BuiltinLoc,
     }
   }
 
-  if (!IsMS && !E->isTypeDependent() &&
+  if ((VAKind != VAArgExpr::VA_MS) && !E->isTypeDependent() &&
       !Context.hasSameType(VaListType, E->getType()))
     return ExprError(
         Diag(E->getBeginLoc(),
@@ -17358,7 +17376,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation 
BuiltinLoc,
   }
 
   QualType T = TInfo->getType().getNonLValueExprType(Context);
-  return new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T, IsMS);
+  return new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T, VAKind);
 }
 
 ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
diff --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index 74a7b51368c28..8805ef6fa592d 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -8524,6 +8524,12 @@ Decl *ASTReader::getPredefinedDecl(PredefinedDeclIDs ID) 
{
     NewLoaded = Context.getBuiltinMSVaListDecl();
     break;
 
+  case PREDEF_DECL_BUILTIN_ZOS_VA_LIST_ID:
+    if (Context.BuiltinZOSVaListDecl)
+      return Context.BuiltinZOSVaListDecl;
+    NewLoaded = Context.getBuiltinZOSVaListDecl();
+    break;
+
   case PREDEF_DECL_BUILTIN_MS_GUID_ID:
     // ASTContext::getMSGuidTagDecl won't create MSGuidTagDecl conditionally.
     return Context.getMSGuidTagDecl();
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index 02ccf8d4d41c2..c75b9f3598711 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1372,7 +1372,7 @@ void ASTStmtReader::VisitVAArgExpr(VAArgExpr *E) {
   E->setWrittenTypeInfo(readTypeSourceInfo());
   E->setBuiltinLoc(readSourceLocation());
   E->setRParenLoc(readSourceLocation());
-  E->setIsMicrosoftABI(Record.readInt());
+  E->setVarargABI(Record.readInt());
 }
 
 void ASTStmtReader::VisitSourceLocExpr(SourceLocExpr *E) {
diff --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index 074b0fccdb65d..d0162960efd25 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5742,6 +5742,8 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) 
{
   RegisterPredefDecl(Context.VaListTagDecl, PREDEF_DECL_VA_LIST_TAG);
   RegisterPredefDecl(Context.BuiltinMSVaListDecl,
                      PREDEF_DECL_BUILTIN_MS_VA_LIST_ID);
+  RegisterPredefDecl(Context.BuiltinZOSVaListDecl,
+                     PREDEF_DECL_BUILTIN_ZOS_VA_LIST_ID);
   RegisterPredefDecl(Context.MSGuidTagDecl,
                      PREDEF_DECL_BUILTIN_MS_GUID_ID);
   RegisterPredefDecl(Context.MSTypeInfoTagDecl,

>From 78ca9ed196386056c2935e96e8b59ed21f83bda8 Mon Sep 17 00:00:00 2001
From: Sean Perry <[email protected]>
Date: Fri, 5 Jun 2026 20:29:48 -0400
Subject: [PATCH 2/4] update the abi tests to include va_lists

---
 clang/test/CodeGen/SystemZ/zos-abi.c | 154 ++++++++++++++
 clang/test/CodeGen/zos-abi.c         | 307 +++++++++++++++++++++++++++
 2 files changed, 461 insertions(+)
 create mode 100644 clang/test/CodeGen/zos-abi.c

diff --git a/clang/test/CodeGen/SystemZ/zos-abi.c 
b/clang/test/CodeGen/SystemZ/zos-abi.c
index ac1d7b31328b6..60e058cf3167a 100644
--- a/clang/test/CodeGen/SystemZ/zos-abi.c
+++ b/clang/test/CodeGen/SystemZ/zos-abi.c
@@ -486,3 +486,157 @@ union tu_long pass_tu_long(union tu_long arg) { return 
arg; }
 union tu_ptr { void *a; } __attribute__((transparent_union));
 union tu_ptr pass_tu_ptr(union tu_ptr arg) { return arg; }
 // CHECK-LABEL: define{{.*}} ptr @pass_tu_ptr(ptr %{{.*}})
+
+
+// =================================================================
+// Accessing variable argument lists
+// =================================================================
+
+// z/OS has two different implementations for variable argument handling.
+// Functions ending with _e test the extended variant of vararg functions
+// (__builtin_va_start, __builtin_va_arg, __builtin_va_end). The type of
+// va_list is __builtin_va_list.
+// Functions ending with _s test the standard variant of vararg functions
+// (__builtin_zos_va_start, __builtin_va_arg, __builtin_zos_va_end). The type 
of
+// va_list is __builtin_va_list.
+
+int dofmt_e(const char *fmt, ...) {
+  __builtin_va_list va;
+
+  __builtin_va_start(va, fmt);
+  int v = __builtin_va_arg(va, int);
+  __builtin_va_end(va);
+
+  return v;
+}
+// CHECK-LABEL: define signext i32 @dofmt_e(ptr %{{.*}}, ...)
+// CHECK: [[FMT_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: [[VA:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: [[V:%[._a-z0-9]+]] = alloca i32, align 4
+// CHECK: store ptr %{{.*}}, ptr [[FMT_ADDR]], align 8
+// CHECK: call void @llvm.va_start.p0(ptr [[VA]])
+// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[VA]], align 8
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
+// CHECK: store ptr [[ARGP_NEXT]], ptr [[VA]], align 8
+// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 4
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK: store i32 [[VAL]], ptr [[V]], align 4
+// CHECK: call void @llvm.va_end.p0(ptr [[VA]])
+// CHECK: [[VAL2:%[._a-z0-9]+]] = load i32, ptr [[V]], align 4
+// CHECK: ret i32 [[VAL2]]
+
+int dofmt_s(const char *fmt, ...) {
+  __builtin_zos_va_list va;
+
+  __builtin_zos_va_start(va, fmt);
+  int v = __builtin_va_arg(va, int);
+  __builtin_zos_va_end(va);
+
+  return v;
+}
+// CHECK-LABEL: define signext i32 @dofmt_s(ptr %{{.*}}, ...)
+// CHECK: [[FMT_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: [[VA:%[._a-z0-9]+]] = alloca [2 x ptr], align 8
+// CHECK: [[V:%[._a-z0-9]+]] = alloca i32, align 4
+// CHECK: store ptr %{{.*}}, ptr [[FMT_ADDR]], align 8
+// CHECK: [[DECAY1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
+// CHECK: [[VALIST_CURR1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY1]], i64 0, i64 0
+// CHECK: store ptr null, ptr [[VALIST_CURR1]], align 8
+// CHECK: [[VALIST_NEXT1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY1]], i64 0, i64 1
+// CHECK: call void @llvm.va_start.p0(ptr [[VALIST_NEXT1]])
+// CHECK: [[DECAY2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
+// CHECK: [[VALIST_CURR2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY2]], i64 0, i64 0
+// CHECK: [[VALIST_NEXT2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY2]], i64 0, i64 1
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT2]], align 8
+// CHECK: %0 = getelementptr inbounds i8, ptr [[ARGP_NEXT]], i32 7
+// CHECK: [[ARGP_NEXT_ALIGNED:%[._a-z0-9]+]] = call ptr 
@llvm.ptrmask.p0.i64(ptr %0, i64 -8)
+// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR2]], align 8
+// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
+// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT2]], align 8
+// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK: store i32 [[VAL]], ptr [[V]], align 4
+// CHECK: [[DECAY3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
+// CHECK: [[VALIST_CURR3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY3]], i64 0, i64 0
+// CHECK: store ptr null, ptr [[VALIST_CURR3]], align 8
+// CHECK: [[VALIST_NEXT3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY3]], i64 0, i64 1
+// CHECK: call void @llvm.va_end.p0(ptr [[VALIST_NEXT3]])
+// CHECK: [[VAL2:%[._a-z0-9]+]] = load i32, ptr [[V]], align 4
+// CHECK: ret i32 [[VAL2]]
+
+int va_int_e(__builtin_va_list l) { return __builtin_va_arg(l, int); }
+// CHECK-LABEL: define signext i32 @va_int_e(ptr %{{.*}})
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
+// CHECK: store ptr [[ARGP_NEXT]], ptr [[L_ADDR]], align 8
+// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 4
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK: ret i32 [[VAL]]
+
+int va_int_s(__builtin_zos_va_list l) { return __builtin_va_arg(l, int); }
+// CHECK-LABEL: define signext i32 @va_int_s(ptr %{{.*}})
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
+// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
+// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
+// CHECK: [[ARGP_NEXT_ALIGNED]] = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
+// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
+// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
+// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
+// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK: ret i32 [[VAL]]
+
+long va_long_e(__builtin_va_list l) { return __builtin_va_arg(l, long); }
+// CHECK-LABEL: define signext i64 @va_long_e(ptr %{{.*}})
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
+// CHECK: store ptr [[ARGP_NEXT]], ptr [[L_ADDR]], align 8
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i64, ptr [[ARGP_CURR]], align 8
+// CHECK: ret i64 [[VAL]]
+
+long va_long_s(__builtin_zos_va_list l) { return __builtin_va_arg(l, long); }
+// CHECK-LABEL: define signext i64 @va_long_s(ptr %{{.*}})
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
+// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
+// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
+// CHECK: %arg.next.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
+// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
+// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 8
+// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i64, ptr [[ARGP_NEXT_ALIGNED]], align 8
+// CHECK: ret i64 [[VAL]]
+
+struct agg_threedouble {
+  double a, b, c;
+};
+struct agg_threedouble va_3double_s(__builtin_zos_va_list l) {
+  return __builtin_va_arg(l, struct agg_threedouble);
+}
+// CHECK-LABEL: define inreg [3 x i64] @va_3double_s(ptr %{{.*}})
+// CHECK: [[RETVAL:%[._a-z0-9]+]] = alloca %struct.agg_threedouble, align 8
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
+// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
+// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
+// CHECK: [[ARGP_NEXT_ALIGNED]] = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
+// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
+// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 24
+// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
+// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 
[[ARGP_NEXT_ALIGNED]], i64 24, i1 false)
+// CHECK: [[RETVAL2:%[._a-z0-9]+]] = load [3 x i64], ptr [[RETVAL]], align 8
+// CHECK: ret [3 x i64] [[RETVAL2]]
diff --git a/clang/test/CodeGen/zos-abi.c b/clang/test/CodeGen/zos-abi.c
new file mode 100644
index 0000000000000..1d505115f7f77
--- /dev/null
+++ b/clang/test/CodeGen/zos-abi.c
@@ -0,0 +1,307 @@
+// RUN: %clang_cc1 -triple s390x-ibm-zos \
+// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-feature +vector \
+// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z13 \
+// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch11 \
+// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z14 \
+// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch12 \
+// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z15 \
+// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch13 \
+// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
+
+// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch11 \
+// RUN:   -DTEST_VEC -fzvector -emit-llvm -no-enable-noundef-analysis \
+// RUN:   -o - %s | FileCheck --check-prefixes=CHECK,CHECKVEC,CHECKI128 %s
+
+// Scalar types
+
+signed char pass_schar(signed char arg) { return arg; }
+// CHECK-LABEL: define signext i8 @pass_schar(i8 signext %{{.*}})
+
+unsigned char pass_uchar(unsigned char arg) { return arg; }
+// CHECK-LABEL: define zeroext i8 @pass_uchar(i8 zeroext %{{.*}})
+
+short pass_short(short arg) { return arg; }
+// CHECK-LABEL: define signext i16 @pass_short(i16 signext %{{.*}})
+
+int pass_int(int arg) { return arg; }
+// CHECK-LABEL: define signext i32 @pass_int(i32 signext %{{.*}})
+
+long pass_long(long arg) { return arg; }
+// CHECK-LABEL: define signext i64 @pass_long(i64 signext %{{.*}})
+
+long long pass_longlong(long long arg) { return arg; }
+// CHECK-LABEL: define i64 @pass_longlong(i64 %{{.*}})
+
+#ifdef __VX__
+__int128 pass_int128(__int128 arg) { return arg; }
+// CHECKI128-LABEL: define i128 @pass_int128(i128 %{{.*}})
+#endif
+
+float pass_float(float arg) { return arg; }
+// CHECK-LABEL: define float @pass_float(float %{{.*}})
+
+double pass_double(double arg) { return arg; }
+// CHECK-LABEL: define double @pass_double(double %{{.*}})
+
+long double pass_longdouble(long double arg) { return arg; }
+// CHECK-LABEL: define fp128 @pass_longdouble(fp128 %{{.*}})
+
+enum Color { Red, Blue };
+enum Color pass_enum(enum Color arg) { return arg; }
+// CHECK-LABEL: define zeroext i32 @pass_enum(i32 zeroext %{{.*}})
+
+#ifdef TEST_VEC
+vector unsigned int pass_vector(vector unsigned int arg) { return arg; };
+// CHECKVEC-LABEL: define <4 x i32> @pass_vector(<4 x i32> %{{.*}})
+
+struct SingleVec { vector unsigned int v; };
+struct SingleVec pass_SingleVec_agg(struct SingleVec arg) { return arg; };
+// CHECKVEC-LABEL: define inreg [2 x i64] @pass_SingleVec_agg([2 x i64] 
%{{.*}})
+#endif
+
+// Complex types
+
+_Complex float pass_complex_float(_Complex float arg) { return arg; }
+// CHECK-LABEL: define { float, float } @pass_complex_float({ float, float } 
%{{.*}})
+
+_Complex double pass_complex_double(_Complex double arg) { return arg; }
+// CHECK-LABEL: define { double, double } @pass_complex_double({ double, 
double } %{{.*}})
+
+_Complex long double pass_complex_longdouble(_Complex long double arg) { 
return arg; }
+// CHECK-LABEL: define { fp128, fp128 } @pass_complex_longdouble({ fp128, 
fp128 } %{{.*}})
+
+// Verify that the following are complex-like types
+struct complexlike_float { float re, im; };
+struct complexlike_float pass_complexlike_float(struct complexlike_float arg) 
{ return arg; }
+// CHECK-LABEL: define %struct.complexlike_float @pass_complexlike_float({ 
float, float } %{{.*}})
+
+struct complexlike_double { double re, im; };
+struct complexlike_double pass_complexlike_double(struct complexlike_double 
arg) { return arg; }
+// CHECK-LABEL: define %struct.complexlike_double @pass_complexlike_double({ 
double, double } %{{.*}})
+
+struct complexlike_longdouble { long double re, im; };
+struct complexlike_longdouble pass_complexlike_longdouble(struct 
complexlike_longdouble arg) { return arg; }
+// CHECK-LABEL: define %struct.complexlike_longdouble 
@pass_complexlike_longdouble({ fp128, fp128 } %{{.*}})
+
+// Aggregate types
+
+struct agg_1byte { char a[1]; };
+struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_1byte(i64 %{{.*}})
+
+struct agg_2byte { char a[2]; };
+struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_2byte(i64 %{{.*}})
+
+struct agg_3byte { char a[3]; };
+struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_3byte(i64 %{{.*}})
+
+struct agg_4byte { char a[4]; };
+struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_4byte(i64 %{{.*}})
+
+struct agg_5byte { char a[5]; };
+struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_5byte(i64 %{{.*}})
+
+struct agg_6byte { char a[6]; };
+struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_6byte(i64 %{{.*}})
+
+struct agg_7byte { char a[7]; };
+struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_7byte(i64 %{{.*}})
+
+struct agg_8byte { char a[8]; };
+struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_8byte(i64 %{{.*}})
+
+struct agg_9byte { char a[9]; };
+struct agg_9byte pass_agg_9byte(struct agg_9byte arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @pass_agg_9byte([2 x i64] %{{.*}})
+
+struct agg_16byte { char a[16]; };
+struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; }
+// CHECK-LABEL: define inreg [2 x i64] @pass_agg_16byte([2 x i64] %{{.*}})
+
+struct agg_24byte { char a[24]; };
+struct agg_24byte pass_agg_24byte(struct agg_24byte arg) { return arg; }
+// CHECK-LABEL: define inreg [3 x i64] @pass_agg_24byte([3 x i64] %{{.*}})
+
+struct agg_25byte { char a[25]; };
+struct agg_25byte pass_agg_25byte(struct agg_25byte arg) { return arg; }
+// CHECK-LABEL: define void @pass_agg_25byte(ptr dead_on_unwind noalias 
writable sret{{.*}} align 1 %{{.*}}, [4 x i64] %{{.*}})
+
+// Check that a float-like aggregate type is really passed as aggregate
+struct agg_float { float a; };
+struct agg_float pass_agg_float(struct agg_float arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_float(i64 %{{.*}})
+
+// Verify that the following are *not* float-like aggregate types
+
+struct agg_nofloat2 { float a; int b; };
+struct agg_nofloat2 pass_agg_nofloat2(struct agg_nofloat2 arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_nofloat2(i64 %{{.*}})
+
+struct agg_nofloat3 { float a; int : 0; };
+struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; }
+// CHECK-LABEL: define inreg [1 x i64] @pass_agg_nofloat3(i64 %{{.*}})
+
+// Accessing variable argument lists
+
+// z/OS has two different implementations for variable argument handling.
+// Functions ending with _e test the extended variant of vararg functions
+// (__builtin_va_start, __builtin_va_arg, __builtin_va_end). The type of
+// va_list is __builtin_va_list.
+// Functions ending with _s test the standard variant of vararg functions
+// (__builtin_zos_va_start, __builtin_va_arg, __builtin_zos_va_end). The type 
of
+// va_list is __builtin_va_list.
+
+int dofmt_e(const char *fmt, ...) {
+  __builtin_va_list va;
+
+  __builtin_va_start(va, fmt);
+  int v = __builtin_va_arg(va, int);
+  __builtin_va_end(va);
+
+  return v;
+}
+// CHECK-LABEL: define signext i32 @dofmt_e(ptr %{{.*}}, ...)
+// CHECK: [[FMT_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: [[VA:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: [[V:%[._a-z0-9]+]] = alloca i32, align 4
+// CHECK: store ptr %{{.*}}, ptr [[FMT_ADDR]], align 8
+// CHECK: call void @llvm.va_start.p0(ptr [[VA]])
+// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[VA]], align 8
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
+// CHECK: store ptr [[ARGP_NEXT]], ptr [[VA]], align 8
+// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 4
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK: store i32 [[VAL]], ptr [[V]], align 4
+// CHECK: call void @llvm.va_end.p0(ptr [[VA]])
+// CHECK: [[VAL2:%[._a-z0-9]+]] = load i32, ptr [[V]], align 4
+// CHECK: ret i32 [[VAL2]]
+
+int dofmt_s(const char *fmt, ...) {
+  __builtin_zos_va_list va;
+
+  __builtin_zos_va_start(va, fmt);
+  int v = __builtin_va_arg(va, int);
+  __builtin_zos_va_end(va);
+
+  return v;
+}
+// CHECK-LABEL: define signext i32 @dofmt_s(ptr %{{.*}}, ...)
+// CHECK: [[FMT_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: [[VA:%[._a-z0-9]+]] = alloca [2 x ptr], align 8
+// CHECK: [[V:%[._a-z0-9]+]] = alloca i32, align 4
+// CHECK: store ptr %{{.*}}, ptr [[FMT_ADDR]], align 8
+// CHECK: [[DECAY1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
+// CHECK: [[VALIST_CURR1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY1]], i64 0, i64 0
+// CHECK: store ptr null, ptr [[VALIST_CURR1]], align 8
+// CHECK: [[VALIST_NEXT1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY1]], i64 0, i64 1
+// CHECK: call void @llvm.va_start.p0(ptr [[VALIST_NEXT1]])
+// CHECK: [[DECAY2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
+// CHECK: [[VALIST_CURR2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY2]], i64 0, i64 0
+// CHECK: [[VALIST_NEXT2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY2]], i64 0, i64 1
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT2]], align 8
+// CHECK: %0 = getelementptr inbounds i8, ptr [[ARGP_NEXT]], i32 7
+// CHECK: [[ARGP_NEXT_ALIGNED:%[._a-z0-9]+]] = call ptr 
@llvm.ptrmask.p0.i64(ptr %0, i64 -8)
+// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR2]], align 8
+// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
+// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT2]], align 8
+// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK: store i32 [[VAL]], ptr [[V]], align 4
+// CHECK: [[DECAY3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
+// CHECK: [[VALIST_CURR3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY3]], i64 0, i64 0
+// CHECK: store ptr null, ptr [[VALIST_CURR3]], align 8
+// CHECK: [[VALIST_NEXT3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY3]], i64 0, i64 1
+// CHECK: call void @llvm.va_end.p0(ptr [[VALIST_NEXT3]])
+// CHECK: [[VAL2:%[._a-z0-9]+]] = load i32, ptr [[V]], align 4
+// CHECK: ret i32 [[VAL2]]
+
+int va_int_e(__builtin_va_list l) { return __builtin_va_arg(l, int); }
+// CHECK-LABEL: define signext i32 @va_int_e(ptr %{{.*}})
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
+// CHECK: store ptr [[ARGP_NEXT]], ptr [[L_ADDR]], align 8
+// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 4
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK: ret i32 [[VAL]]
+
+int va_int_s(__builtin_zos_va_list l) { return __builtin_va_arg(l, int); }
+// CHECK-LABEL: define signext i32 @va_int_s(ptr %{{.*}})
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
+// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
+// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
+// CHECK: [[ARGP_NEXT_ALIGNED]] = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
+// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
+// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
+// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
+// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
+// CHECK: ret i32 [[VAL]]
+
+long va_long_e(__builtin_va_list l) { return __builtin_va_arg(l, long); }
+// CHECK-LABEL: define signext i64 @va_long_e(ptr %{{.*}})
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
+// CHECK: store ptr [[ARGP_NEXT]], ptr [[L_ADDR]], align 8
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i64, ptr [[ARGP_CURR]], align 8
+// CHECK: ret i64 [[VAL]]
+
+long va_long_s(__builtin_zos_va_list l) { return __builtin_va_arg(l, long); }
+// CHECK-LABEL: define signext i64 @va_long_s(ptr %{{.*}})
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
+// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
+// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
+// CHECK: %arg.next.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
+// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
+// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 8
+// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
+// CHECK: [[VAL:%[._a-z0-9]+]] = load i64, ptr [[ARGP_NEXT_ALIGNED]], align 8
+// CHECK: ret i64 [[VAL]]
+
+struct agg_threedouble {
+  double a, b, c;
+};
+struct agg_threedouble va_3double_s(__builtin_zos_va_list l) {
+  return __builtin_va_arg(l, struct agg_threedouble);
+}
+// CHECK-LABEL: define inreg [3 x i64] @va_3double_s(ptr %{{.*}})
+// CHECK: [[RETVAL:%[._a-z0-9]+]] = alloca %struct.agg_threedouble, align 8
+// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
+// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
+// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
+// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
+// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
+// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
+// CHECK: [[ARGP_NEXT_ALIGNED]] = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
+// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
+// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 24
+// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
+// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 
[[ARGP_NEXT_ALIGNED]], i64 24, i1 false)
+// CHECK: [[RETVAL2:%[._a-z0-9]+]] = load [3 x i64], ptr [[RETVAL]], align 8
+// CHECK: ret [3 x i64] [[RETVAL2]]

>From 7520032f34f7b91f5a59c6ad245a7c6bba7d85f1 Mon Sep 17 00:00:00 2001
From: Sean Perry <[email protected]>
Date: Mon, 8 Jun 2026 13:41:46 -0400
Subject: [PATCH 3/4] remove file

---
 clang/test/CodeGen/zos-abi.c | 307 -----------------------------------
 1 file changed, 307 deletions(-)
 delete mode 100644 clang/test/CodeGen/zos-abi.c

diff --git a/clang/test/CodeGen/zos-abi.c b/clang/test/CodeGen/zos-abi.c
deleted file mode 100644
index 1d505115f7f77..0000000000000
--- a/clang/test/CodeGen/zos-abi.c
+++ /dev/null
@@ -1,307 +0,0 @@
-// RUN: %clang_cc1 -triple s390x-ibm-zos \
-// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple s390x-ibm-zos -target-feature +vector \
-// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
-// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z13 \
-// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
-// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch11 \
-// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
-// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z14 \
-// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
-// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch12 \
-// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
-// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu z15 \
-// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
-// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch13 \
-// RUN:   -emit-llvm -no-enable-noundef-analysis -o - %s | FileCheck 
--check-prefixes=CHECK,CHECKI128 %s
-
-// RUN: %clang_cc1 -triple s390x-ibm-zos -target-cpu arch11 \
-// RUN:   -DTEST_VEC -fzvector -emit-llvm -no-enable-noundef-analysis \
-// RUN:   -o - %s | FileCheck --check-prefixes=CHECK,CHECKVEC,CHECKI128 %s
-
-// Scalar types
-
-signed char pass_schar(signed char arg) { return arg; }
-// CHECK-LABEL: define signext i8 @pass_schar(i8 signext %{{.*}})
-
-unsigned char pass_uchar(unsigned char arg) { return arg; }
-// CHECK-LABEL: define zeroext i8 @pass_uchar(i8 zeroext %{{.*}})
-
-short pass_short(short arg) { return arg; }
-// CHECK-LABEL: define signext i16 @pass_short(i16 signext %{{.*}})
-
-int pass_int(int arg) { return arg; }
-// CHECK-LABEL: define signext i32 @pass_int(i32 signext %{{.*}})
-
-long pass_long(long arg) { return arg; }
-// CHECK-LABEL: define signext i64 @pass_long(i64 signext %{{.*}})
-
-long long pass_longlong(long long arg) { return arg; }
-// CHECK-LABEL: define i64 @pass_longlong(i64 %{{.*}})
-
-#ifdef __VX__
-__int128 pass_int128(__int128 arg) { return arg; }
-// CHECKI128-LABEL: define i128 @pass_int128(i128 %{{.*}})
-#endif
-
-float pass_float(float arg) { return arg; }
-// CHECK-LABEL: define float @pass_float(float %{{.*}})
-
-double pass_double(double arg) { return arg; }
-// CHECK-LABEL: define double @pass_double(double %{{.*}})
-
-long double pass_longdouble(long double arg) { return arg; }
-// CHECK-LABEL: define fp128 @pass_longdouble(fp128 %{{.*}})
-
-enum Color { Red, Blue };
-enum Color pass_enum(enum Color arg) { return arg; }
-// CHECK-LABEL: define zeroext i32 @pass_enum(i32 zeroext %{{.*}})
-
-#ifdef TEST_VEC
-vector unsigned int pass_vector(vector unsigned int arg) { return arg; };
-// CHECKVEC-LABEL: define <4 x i32> @pass_vector(<4 x i32> %{{.*}})
-
-struct SingleVec { vector unsigned int v; };
-struct SingleVec pass_SingleVec_agg(struct SingleVec arg) { return arg; };
-// CHECKVEC-LABEL: define inreg [2 x i64] @pass_SingleVec_agg([2 x i64] 
%{{.*}})
-#endif
-
-// Complex types
-
-_Complex float pass_complex_float(_Complex float arg) { return arg; }
-// CHECK-LABEL: define { float, float } @pass_complex_float({ float, float } 
%{{.*}})
-
-_Complex double pass_complex_double(_Complex double arg) { return arg; }
-// CHECK-LABEL: define { double, double } @pass_complex_double({ double, 
double } %{{.*}})
-
-_Complex long double pass_complex_longdouble(_Complex long double arg) { 
return arg; }
-// CHECK-LABEL: define { fp128, fp128 } @pass_complex_longdouble({ fp128, 
fp128 } %{{.*}})
-
-// Verify that the following are complex-like types
-struct complexlike_float { float re, im; };
-struct complexlike_float pass_complexlike_float(struct complexlike_float arg) 
{ return arg; }
-// CHECK-LABEL: define %struct.complexlike_float @pass_complexlike_float({ 
float, float } %{{.*}})
-
-struct complexlike_double { double re, im; };
-struct complexlike_double pass_complexlike_double(struct complexlike_double 
arg) { return arg; }
-// CHECK-LABEL: define %struct.complexlike_double @pass_complexlike_double({ 
double, double } %{{.*}})
-
-struct complexlike_longdouble { long double re, im; };
-struct complexlike_longdouble pass_complexlike_longdouble(struct 
complexlike_longdouble arg) { return arg; }
-// CHECK-LABEL: define %struct.complexlike_longdouble 
@pass_complexlike_longdouble({ fp128, fp128 } %{{.*}})
-
-// Aggregate types
-
-struct agg_1byte { char a[1]; };
-struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_1byte(i64 %{{.*}})
-
-struct agg_2byte { char a[2]; };
-struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_2byte(i64 %{{.*}})
-
-struct agg_3byte { char a[3]; };
-struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_3byte(i64 %{{.*}})
-
-struct agg_4byte { char a[4]; };
-struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_4byte(i64 %{{.*}})
-
-struct agg_5byte { char a[5]; };
-struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_5byte(i64 %{{.*}})
-
-struct agg_6byte { char a[6]; };
-struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_6byte(i64 %{{.*}})
-
-struct agg_7byte { char a[7]; };
-struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_7byte(i64 %{{.*}})
-
-struct agg_8byte { char a[8]; };
-struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_8byte(i64 %{{.*}})
-
-struct agg_9byte { char a[9]; };
-struct agg_9byte pass_agg_9byte(struct agg_9byte arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_agg_9byte([2 x i64] %{{.*}})
-
-struct agg_16byte { char a[16]; };
-struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; }
-// CHECK-LABEL: define inreg [2 x i64] @pass_agg_16byte([2 x i64] %{{.*}})
-
-struct agg_24byte { char a[24]; };
-struct agg_24byte pass_agg_24byte(struct agg_24byte arg) { return arg; }
-// CHECK-LABEL: define inreg [3 x i64] @pass_agg_24byte([3 x i64] %{{.*}})
-
-struct agg_25byte { char a[25]; };
-struct agg_25byte pass_agg_25byte(struct agg_25byte arg) { return arg; }
-// CHECK-LABEL: define void @pass_agg_25byte(ptr dead_on_unwind noalias 
writable sret{{.*}} align 1 %{{.*}}, [4 x i64] %{{.*}})
-
-// Check that a float-like aggregate type is really passed as aggregate
-struct agg_float { float a; };
-struct agg_float pass_agg_float(struct agg_float arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_float(i64 %{{.*}})
-
-// Verify that the following are *not* float-like aggregate types
-
-struct agg_nofloat2 { float a; int b; };
-struct agg_nofloat2 pass_agg_nofloat2(struct agg_nofloat2 arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_nofloat2(i64 %{{.*}})
-
-struct agg_nofloat3 { float a; int : 0; };
-struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; }
-// CHECK-LABEL: define inreg [1 x i64] @pass_agg_nofloat3(i64 %{{.*}})
-
-// Accessing variable argument lists
-
-// z/OS has two different implementations for variable argument handling.
-// Functions ending with _e test the extended variant of vararg functions
-// (__builtin_va_start, __builtin_va_arg, __builtin_va_end). The type of
-// va_list is __builtin_va_list.
-// Functions ending with _s test the standard variant of vararg functions
-// (__builtin_zos_va_start, __builtin_va_arg, __builtin_zos_va_end). The type 
of
-// va_list is __builtin_va_list.
-
-int dofmt_e(const char *fmt, ...) {
-  __builtin_va_list va;
-
-  __builtin_va_start(va, fmt);
-  int v = __builtin_va_arg(va, int);
-  __builtin_va_end(va);
-
-  return v;
-}
-// CHECK-LABEL: define signext i32 @dofmt_e(ptr %{{.*}}, ...)
-// CHECK: [[FMT_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
-// CHECK: [[VA:%[._a-z0-9]+]] = alloca ptr, align 8
-// CHECK: [[V:%[._a-z0-9]+]] = alloca i32, align 4
-// CHECK: store ptr %{{.*}}, ptr [[FMT_ADDR]], align 8
-// CHECK: call void @llvm.va_start.p0(ptr [[VA]])
-// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[VA]], align 8
-// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
-// CHECK: store ptr [[ARGP_NEXT]], ptr [[VA]], align 8
-// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 4
-// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
-// CHECK: store i32 [[VAL]], ptr [[V]], align 4
-// CHECK: call void @llvm.va_end.p0(ptr [[VA]])
-// CHECK: [[VAL2:%[._a-z0-9]+]] = load i32, ptr [[V]], align 4
-// CHECK: ret i32 [[VAL2]]
-
-int dofmt_s(const char *fmt, ...) {
-  __builtin_zos_va_list va;
-
-  __builtin_zos_va_start(va, fmt);
-  int v = __builtin_va_arg(va, int);
-  __builtin_zos_va_end(va);
-
-  return v;
-}
-// CHECK-LABEL: define signext i32 @dofmt_s(ptr %{{.*}}, ...)
-// CHECK: [[FMT_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
-// CHECK: [[VA:%[._a-z0-9]+]] = alloca [2 x ptr], align 8
-// CHECK: [[V:%[._a-z0-9]+]] = alloca i32, align 4
-// CHECK: store ptr %{{.*}}, ptr [[FMT_ADDR]], align 8
-// CHECK: [[DECAY1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
-// CHECK: [[VALIST_CURR1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY1]], i64 0, i64 0
-// CHECK: store ptr null, ptr [[VALIST_CURR1]], align 8
-// CHECK: [[VALIST_NEXT1:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY1]], i64 0, i64 1
-// CHECK: call void @llvm.va_start.p0(ptr [[VALIST_NEXT1]])
-// CHECK: [[DECAY2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
-// CHECK: [[VALIST_CURR2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY2]], i64 0, i64 0
-// CHECK: [[VALIST_NEXT2:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY2]], i64 0, i64 1
-// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT2]], align 8
-// CHECK: %0 = getelementptr inbounds i8, ptr [[ARGP_NEXT]], i32 7
-// CHECK: [[ARGP_NEXT_ALIGNED:%[._a-z0-9]+]] = call ptr 
@llvm.ptrmask.p0.i64(ptr %0, i64 -8)
-// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR2]], align 8
-// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
-// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT2]], align 8
-// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
-// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
-// CHECK: store i32 [[VAL]], ptr [[V]], align 4
-// CHECK: [[DECAY3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VA]], i64 0, i64 0
-// CHECK: [[VALIST_CURR3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY3]], i64 0, i64 0
-// CHECK: store ptr null, ptr [[VALIST_CURR3]], align 8
-// CHECK: [[VALIST_NEXT3:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], 
ptr [[DECAY3]], i64 0, i64 1
-// CHECK: call void @llvm.va_end.p0(ptr [[VALIST_NEXT3]])
-// CHECK: [[VAL2:%[._a-z0-9]+]] = load i32, ptr [[V]], align 4
-// CHECK: ret i32 [[VAL2]]
-
-int va_int_e(__builtin_va_list l) { return __builtin_va_arg(l, int); }
-// CHECK-LABEL: define signext i32 @va_int_e(ptr %{{.*}})
-// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
-// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
-// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
-// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
-// CHECK: store ptr [[ARGP_NEXT]], ptr [[L_ADDR]], align 8
-// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 4
-// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
-// CHECK: ret i32 [[VAL]]
-
-int va_int_s(__builtin_zos_va_list l) { return __builtin_va_arg(l, int); }
-// CHECK-LABEL: define signext i32 @va_int_s(ptr %{{.*}})
-// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
-// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
-// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
-// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
-// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
-// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
-// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
-// CHECK: [[ARGP_NEXT_ALIGNED]] = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
-// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
-// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
-// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
-// CHECK: [[V_ADDR:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 4
-// CHECK: [[VAL:%[._a-z0-9]+]] = load i32, ptr [[V_ADDR]], align 4
-// CHECK: ret i32 [[VAL]]
-
-long va_long_e(__builtin_va_list l) { return __builtin_va_arg(l, long); }
-// CHECK-LABEL: define signext i64 @va_long_e(ptr %{{.*}})
-// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
-// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
-// CHECK: [[ARGP_CURR:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
-// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_CURR]], i64 8
-// CHECK: store ptr [[ARGP_NEXT]], ptr [[L_ADDR]], align 8
-// CHECK: [[VAL:%[._a-z0-9]+]] = load i64, ptr [[ARGP_CURR]], align 8
-// CHECK: ret i64 [[VAL]]
-
-long va_long_s(__builtin_zos_va_list l) { return __builtin_va_arg(l, long); }
-// CHECK-LABEL: define signext i64 @va_long_s(ptr %{{.*}})
-// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
-// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
-// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
-// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
-// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
-// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
-// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
-// CHECK: %arg.next.aligned = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
-// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
-// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 8
-// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
-// CHECK: [[VAL:%[._a-z0-9]+]] = load i64, ptr [[ARGP_NEXT_ALIGNED]], align 8
-// CHECK: ret i64 [[VAL]]
-
-struct agg_threedouble {
-  double a, b, c;
-};
-struct agg_threedouble va_3double_s(__builtin_zos_va_list l) {
-  return __builtin_va_arg(l, struct agg_threedouble);
-}
-// CHECK-LABEL: define inreg [3 x i64] @va_3double_s(ptr %{{.*}})
-// CHECK: [[RETVAL:%[._a-z0-9]+]] = alloca %struct.agg_threedouble, align 8
-// CHECK: [[L_ADDR:%[._a-z0-9]+]] = alloca ptr, align 8
-// CHECK: store ptr %{{.*}}, ptr [[L_ADDR]], align 8
-// CHECK: [[VALIST:%[._a-z0-9]+]] = load ptr, ptr [[L_ADDR]], align 8
-// CHECK: [[VALIST_CURR:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 0
-// CHECK: [[VALIST_NEXT:%[._a-z0-9]+]] = getelementptr inbounds [2 x ptr], ptr 
[[VALIST]], i64 0, i64 1
-// CHECK: [[ARGP_NEXT:%[._a-z0-9]+]] = load ptr, ptr [[VALIST_NEXT]], align 8
-// CHECK: %1 = getelementptr inbounds i8, ptr %arg.next, i32 7
-// CHECK: [[ARGP_NEXT_ALIGNED]] = call ptr @llvm.ptrmask.p0.i64(ptr %1, i64 -8)
-// CHECK: store ptr [[ARGP_NEXT_ALIGNED]], ptr [[VALIST_CURR]], align 8
-// CHECK: [[ARGP_NEXT_NEXT:%[._a-z0-9]+]] = getelementptr inbounds i8, ptr 
[[ARGP_NEXT_ALIGNED]], i64 24
-// CHECK: store ptr [[ARGP_NEXT_NEXT]], ptr [[VALIST_NEXT]], align 8
-// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 
[[ARGP_NEXT_ALIGNED]], i64 24, i1 false)
-// CHECK: [[RETVAL2:%[._a-z0-9]+]] = load [3 x i64], ptr [[RETVAL]], align 8
-// CHECK: ret [3 x i64] [[RETVAL2]]

>From 17409e0ae86d44105b0bb2983e507e40d7c1270a Mon Sep 17 00:00:00 2001
From: Sean Perry <[email protected]>
Date: Mon, 8 Jun 2026 13:49:21 -0400
Subject: [PATCH 4/4] fix name in comment

---
 clang/lib/AST/ASTContext.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index e3c21b48e90bd..06af5261ed894 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -9996,7 +9996,7 @@ static TypedefDecl *CreateMSVaListDecl(const ASTContext 
*Context) {
 }
 
 static TypedefDecl *CreateZOSVaListDecl(const ASTContext *Context) {
-  // typedef char *__builtin_va_list[2];
+  // typedef char *__builtin_zos_va_list[2];
   llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 2);
   QualType T = Context->getPointerType(Context->CharTy);
   QualType ArrayType = Context->getConstantArrayType(

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to