Ping for the clang SystemZ port that Uli posted here:

http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061170.html
http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130408/077970.html

I've refreshed it against a more recent baseline:

http://llvm-reviews.chandlerc.com/D718

Thanks,
Richard

Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -1578,6 +1578,10 @@
   /// beneficial for performance to overalign a data type.
   unsigned getPreferredTypeAlign(const Type *T) const;
 
+  /// \brief Return the alignment in bytes that should be given to a
+  /// global variable with type \p T.
+  unsigned getGlobalAlign(QualType T) const;
+
   /// \brief Return a conservative estimate of the alignment of the specified
   /// decl \p D.
   ///
Index: include/clang/Basic/TargetInfo.h
===================================================================
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -66,6 +66,7 @@
   unsigned char LongWidth, LongAlign;
   unsigned char LongLongWidth, LongLongAlign;
   unsigned char SuitableAlign;
+  unsigned char MinGlobalAlign;
   unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
   unsigned short MaxVectorAlign;
   const char *DescriptionString;
@@ -156,7 +157,16 @@
     /// __builtin_va_list as defined by ARM AAPCS ABI
     /// http://infocenter.arm.com
     //        /help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
-    AAPCSABIBuiltinVaList
+    AAPCSABIBuiltinVaList,
+
+    // typedef struct __va_list_tag
+    //   {
+    //     long __gpr;
+    //     long __fpr;
+    //     void *__overflow_arg_area;
+    //     void *__reg_save_area;
+    //   } va_list[1];
+    SystemZBuiltinVaList
   };
 
 protected:
@@ -266,6 +276,10 @@
   /// object with a fundamental alignment requirement.
   unsigned getSuitableAlign() const { return SuitableAlign; }
 
+  /// getMinGlobalAlign - Return the minimum alignment of a global variable,
+  /// unless its alignment is explicitly reduced via attributes.
+  unsigned getMinGlobalAlign() const { return MinGlobalAlign; }
+
   /// getWCharWidth/Align - Return the size of 'wchar_t' for this target, in
   /// bits.
   unsigned getWCharWidth() const { return getTypeWidth(WCharType); }
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -1236,6 +1236,10 @@
         T = getBaseElementType(arrayType);
       }
       Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
+      if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+        if (VD->hasGlobalStorage())
+          Align = std::max(Align, getTargetInfo().getMinGlobalAlign());
+      }
     }
 
     // Fields can be subject to extra alignment constraints, like if
@@ -1677,6 +1681,12 @@
   return ABIAlign;
 }
 
+unsigned ASTContext::getGlobalAlign(QualType T) const {
+  unsigned Alignment = getTypeAlignInChars(T).getQuantity();
+  unsigned Base = getTargetInfo().getMinGlobalAlign() / getCharWidth();
+  return std::max(Alignment, Base);
+}
+
 /// DeepCollectObjCIvars -
 /// This routine first collects all declared, but not synthesized, ivars in
 /// super class and then collects all ivars, including those synthesized for
@@ -5893,6 +5903,80 @@
   return VaListTypeDecl;
 }
 
+static TypedefDecl *
+CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
+  // typedef struct __va_list_tag {
+  RecordDecl *VaListTagDecl;
+  VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
+                                   Context->getTranslationUnitDecl(),
+                                   &Context->Idents.get("__va_list_tag"));
+  VaListTagDecl->startDefinition();
+
+  const size_t NumFields = 4;
+  QualType FieldTypes[NumFields];
+  const char *FieldNames[NumFields];
+
+  //   long __gpr;
+  FieldTypes[0] = Context->LongTy;
+  FieldNames[0] = "__gpr";
+
+  //   long __fpr;
+  FieldTypes[1] = Context->LongTy;
+  FieldNames[1] = "__fpr";
+
+  //   void *__overflow_arg_area;
+  FieldTypes[2] = Context->getPointerType(Context->VoidTy);
+  FieldNames[2] = "__overflow_arg_area";
+
+  //   void *__reg_save_area;
+  FieldTypes[3] = Context->getPointerType(Context->VoidTy);
+  FieldNames[3] = "__reg_save_area";
+
+  // Create fields
+  for (unsigned i = 0; i < NumFields; ++i) {
+    FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context),
+                                         VaListTagDecl,
+                                         SourceLocation(),
+                                         SourceLocation(),
+                                         &Context->Idents.get(FieldNames[i]),
+                                         FieldTypes[i], /*TInfo=*/0,
+                                         /*BitWidth=*/0,
+                                         /*Mutable=*/false,
+                                         ICIS_NoInit);
+    Field->setAccess(AS_public);
+    VaListTagDecl->addDecl(Field);
+  }
+  VaListTagDecl->completeDefinition();
+  QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+  Context->VaListTagTy = VaListTagType;
+
+  // } __va_list_tag;
+  TypedefDecl *VaListTagTypedefDecl
+    = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
+                          Context->getTranslationUnitDecl(),
+                          SourceLocation(), SourceLocation(),
+                          &Context->Idents.get("__va_list_tag"),
+                          Context->getTrivialTypeSourceInfo(VaListTagType));
+  QualType VaListTagTypedefType =
+    Context->getTypedefType(VaListTagTypedefDecl);
+
+  // typedef __va_list_tag __builtin_va_list[1];
+  llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
+  QualType VaListTagArrayType
+    = Context->getConstantArrayType(VaListTagTypedefType,
+                                      Size, ArrayType::Normal,0);
+  TypeSourceInfo *TInfo
+    = Context->getTrivialTypeSourceInfo(VaListTagArrayType);
+  TypedefDecl *VaListTypedefDecl
+    = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
+                          Context->getTranslationUnitDecl(),
+                          SourceLocation(), SourceLocation(),
+                          &Context->Idents.get("__builtin_va_list"),
+                          TInfo);
+
+  return VaListTypedefDecl;
+}
+
 static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
                                      TargetInfo::BuiltinVaListKind Kind) {
   switch (Kind) {
@@ -5910,6 +5994,8 @@
     return CreatePNaClABIBuiltinVaListDecl(Context);
   case TargetInfo::AAPCSABIBuiltinVaList:
     return CreateAAPCSABIBuiltinVaListDecl(Context);
+  case TargetInfo::SystemZBuiltinVaList:
+    return CreateSystemZBuiltinVaListDecl(Context);
   }
 
   llvm_unreachable("Unhandled __builtin_va_list type kind");
Index: lib/Basic/TargetInfo.cpp
===================================================================
--- lib/Basic/TargetInfo.cpp
+++ lib/Basic/TargetInfo.cpp
@@ -37,6 +37,7 @@
   LongWidth = LongAlign = 32;
   LongLongWidth = LongLongAlign = 64;
   SuitableAlign = 64;
+  MinGlobalAlign = 0;
   HalfWidth = 16;
   HalfAlign = 16;
   FloatWidth = 32;
Index: lib/Basic/Targets.cpp
===================================================================
--- lib/Basic/Targets.cpp
+++ lib/Basic/Targets.cpp
@@ -4281,6 +4281,123 @@
 } // end anonymous namespace.
 
 namespace {
+  class SystemZTargetInfo : public TargetInfo {
+    static const char *const GCCRegNames[];
+
+  public:
+    SystemZTargetInfo(const std::string& triple) : TargetInfo(triple) {
+      TLSSupported = true;
+      IntWidth = IntAlign = 32;
+      LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
+      PointerWidth = PointerAlign = 64;
+      LongDoubleWidth = 128;
+      LongDoubleAlign = 64;
+      LongDoubleFormat = &llvm::APFloat::IEEEquad;
+      MinGlobalAlign = 16;
+      DescriptionString = "E-p:64:64:64-i1:8:16-i8:8:16-i16:16-i32:32-i64:64"
+       "-f32:32-f64:64-f128:64-a0:8:16-n32:64";
+      MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+    }
+    virtual void getTargetDefines(const LangOptions &Opts,
+                                  MacroBuilder &Builder) const {
+      Builder.defineMacro("__s390__");
+      Builder.defineMacro("__s390x__");
+      Builder.defineMacro("__zarch__");
+      Builder.defineMacro("__LONG_DOUBLE_128__");
+    }
+    virtual void getTargetBuiltins(const Builtin::Info *&Records,
+                                   unsigned &NumRecords) const {
+      // FIXME: Implement.
+      Records = 0;
+      NumRecords = 0;
+    }
+
+    virtual void getGCCRegNames(const char *const *&Names,
+                                unsigned &NumNames) const;
+    virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+                                  unsigned &NumAliases) const {
+      // No aliases.
+      Aliases = 0;
+      NumAliases = 0;
+    }
+    virtual bool validateAsmConstraint(const char *&Name,
+                                       TargetInfo::ConstraintInfo &info) const;
+    virtual const char *getClobbers() const {
+      // FIXME: Is this really right?
+      return "";
+    }
+    virtual BuiltinVaListKind getBuiltinVaListKind() const {
+      return TargetInfo::SystemZBuiltinVaList;
+    }
+  };
+
+  const char *const SystemZTargetInfo::GCCRegNames[] = {
+    "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+    "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+    "f0",  "f2",  "f4",  "f6",  "f1",  "f3",  "f5",  "f7",
+    "f8",  "f10", "f12", "f14", "f9",  "f11", "f13", "f15"
+  };
+
+  void SystemZTargetInfo::getGCCRegNames(const char *const *&Names,
+                                         unsigned &NumNames) const {
+    Names = GCCRegNames;
+    NumNames = llvm::array_lengthof(GCCRegNames);
+  }
+
+  bool SystemZTargetInfo::
+  validateAsmConstraint(const char *&Name,
+                        TargetInfo::ConstraintInfo &Info) const {
+    switch (*Name) {
+    default:
+      return false;
+
+    case 'a': // Address register
+    case 'c': // Condition-code register
+    case 'd': // Data register (equivalent to 'r')
+    case 'f': // Floating-point register
+      Info.setAllowsRegister();
+      return true;
+
+    case 'U': // Address with a 12-bit unsigned displacement
+    case 'W': // Address with a 20-bit signed displacement
+    case 'Y': // A shift value (effectively an address)
+      Info.setAllowsRegister();
+      return true;
+
+    case 'I': // Unsigned 8-bit constant
+    case 'J': // Unsigned 12-bit constant
+    case 'K': // Signed 16-bit constant
+    case 'L': // Signed 20-bit displacement (on all targets we support)
+    case 'M': // 0x7fffffff
+      return true;
+
+    case 'N':
+      // Part number.
+      if (!(Name[1] >= '0' && Name[1] <= '9'))
+        return false;
+      // Part mode (H for 16-bit, Q for 8-bit)
+      if (Name[2] != 'H' && Name[2] != 'Q')
+        return false;
+      // Constant mode (D for 64-bit, S for 32-bit, H for 16-bit)
+      if (Name[3] != 'D' && Name[3] != 'S' && Name[3] != 'H')
+        return false;
+      // Whether the other bits should be clear ('0') or set ('F')
+      if (Name[4] != '0' && Name[4] != 'F')
+        return false;
+      Name += 4;
+      return true;
+
+    case 'Q': // Memory with base and unsigned 12-bit displacement
+    case 'R': // Likewise, plus an index
+    case 'S': // Memory with base and signed 20-bit displacement
+    case 'T': // Likewise, plus an index
+      Info.setAllowsMemory();
+      return true;
+    }
+  }
+}
+
+namespace {
   class MSP430TargetInfo : public TargetInfo {
     static const char * const GCCRegNames[];
   public:
@@ -5247,6 +5364,14 @@
       return new SparcV9TargetInfo(T);
     }
 
+  case llvm::Triple::systemz:
+    switch (os) {
+    case llvm::Triple::Linux:
+      return new LinuxTargetInfo<SystemZTargetInfo>(T);
+    default:
+      return new SystemZTargetInfo(T);
+    }
+
   case llvm::Triple::tce:
     return new TCETargetInfo(T);
 
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -2333,6 +2333,8 @@
     new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/true,
                              Linkage, C, ".str");
   GV->setUnnamedAddr(true);
+  // Don't enforce getGlobalAlign, since the only use of the string
+  // is via this class initializer.
   if (isUTF16) {
     CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
     GV->setAlignment(Align.getQuantity());
@@ -2466,6 +2468,8 @@
   new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
                            ".str");
   GV->setUnnamedAddr(true);
+  // Don't enforce getGlobalAlign, since the only use of the string
+  // is via this class initializer.
   CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
   GV->setAlignment(Align.getQuantity());
   Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros);
@@ -2570,14 +2574,14 @@
 /// constant array for the given string literal.
 llvm::Constant *
 CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
-  CharUnits Align = getContext().getTypeAlignInChars(S->getType());
+  unsigned Alignment = getContext().getGlobalAlign(S->getType());
   if (S->isAscii() || S->isUTF8()) {
     SmallString<64> Str(S->getString());
     
     // Resize the string to the right size, which is indicated by its type.
     const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType());
     Str.resize(CAT->getSize().getZExtValue());
-    return GetAddrOfConstantString(Str, /*GlobalName*/ 0, Align.getQuantity());
+    return GetAddrOfConstantString(Str, /*GlobalName*/ 0, Alignment);
   }
 
   // FIXME: the following does not memoize wide strings.
@@ -2588,7 +2592,7 @@
                              llvm::GlobalValue::PrivateLinkage,
                              C,".str");
 
-  GV->setAlignment(Align.getQuantity());
+  GV->setAlignment(Alignment);
   GV->setUnnamedAddr(true);
   return GV;
 }
@@ -2639,6 +2643,9 @@
   if (!GlobalName)
     GlobalName = ".str";
 
+  if (Alignment == 0)
+    Alignment = getContext().getGlobalAlign(getContext().CharTy);
+
   // Don't share any string literals if strings aren't constant.
   if (LangOpts.WritableStrings)
     return GenerateStringLiteral(Str, false, *this, GlobalName, Alignment);
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -713,7 +713,7 @@
   /// (if one is created).
   llvm::Constant *GetAddrOfConstantString(StringRef Str,
                                           const char *GlobalName=0,
-                                          unsigned Alignment=1);
+                                          unsigned Alignment=0);
 
   /// GetAddrOfConstantCString - Returns a pointer to a character array
   /// containing the literal and a terminating '\0' character. The result has
@@ -723,7 +723,7 @@
   /// created).
   llvm::Constant *GetAddrOfConstantCString(const std::string &str,
                                            const char *GlobalName=0,
-                                           unsigned Alignment=1);
+                                           unsigned Alignment=0);
 
   /// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant global
   /// variable for the given file-scope compound literal expression.
Index: lib/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp
+++ lib/CodeGen/TargetInfo.cpp
@@ -4117,6 +4117,293 @@
 }
 
 //===----------------------------------------------------------------------===//
+// SystemZ ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class SystemZABIInfo : public ABIInfo {
+public:
+  SystemZABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+  bool isPromotableIntegerType(QualType Ty) const;
+  bool isCompoundType(QualType Ty) const;
+  bool isFPArgumentType(QualType Ty) const;
+
+  ABIArgInfo classifyReturnType(QualType RetTy) const;
+  ABIArgInfo classifyArgumentType(QualType ArgTy) const;
+
+  virtual void computeInfo(CGFunctionInfo &FI) const {
+    FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+    for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+         it != ie; ++it)
+      it->info = classifyArgumentType(it->type);
+  }
+
+  virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+                                 CodeGenFunction &CGF) const;
+};
+
+class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+  SystemZTargetCodeGenInfo(CodeGenTypes &CGT)
+    : TargetCodeGenInfo(new SystemZABIInfo(CGT)) {}
+};
+
+}
+
+bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const {
+  // Treat an enum type as its underlying type.
+  if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+    Ty = EnumTy->getDecl()->getIntegerType();
+
+  // Promotable integer types are required to be promoted by the ABI.
+  if (Ty->isPromotableIntegerType())
+    return true;
+
+  // 32-bit values must also be promoted.
+  if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+    switch (BT->getKind()) {
+    case BuiltinType::Int:
+    case BuiltinType::UInt:
+      return true;
+    default:
+      return false;
+    }
+  return false;
+}
+
+bool SystemZABIInfo::isCompoundType(QualType Ty) const {
+  return Ty->isAnyComplexType() || isAggregateTypeForABI(Ty);
+}
+
+bool SystemZABIInfo::isFPArgumentType(QualType Ty) const {
+  if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
+    switch (BT->getKind()) {
+    case BuiltinType::Float:
+    case BuiltinType::Double:
+      return true;
+    default:
+      return false;
+    }
+
+  if (const RecordType *RT = Ty->getAsStructureType()) {
+    const RecordDecl *RD = RT->getDecl();
+    bool Found = false;
+
+    // If this is a C++ record, check the bases first.
+    if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+      for (CXXRecordDecl::base_class_const_iterator I = CXXRD->bases_begin(),
+             E = CXXRD->bases_end(); I != E; ++I) {
+        QualType Base = I->getType();
+
+        // Empty bases don't affect things either way.
+        if (isEmptyRecord(getContext(), Base, true))
+          continue;
+
+        if (Found)
+          return false;
+        Found = isFPArgumentType(Base);
+        if (!Found)
+          return false;
+      }
+
+    // Check the fields.
+    for (RecordDecl::field_iterator I = RD->field_begin(),
+           E = RD->field_end(); I != E; ++I) {
+      const FieldDecl *FD = *I;
+
+      // Empty bitfields don't affect things either way.
+      // Unlike isSingleElementStruct(), empty structure and array fields
+      // do count.  So do anonymous bitfields that aren't zero-sized.
+      if (FD->isBitField() && FD->getBitWidthValue(getContext()) == 0)
+        return true;
+
+      // Unlike isSingleElementStruct(), arrays do not count.
+      // Nested isFPArgumentType structures still do though.
+      if (Found)
+        return false;
+      Found = isFPArgumentType(FD->getType());
+      if (!Found)
+        return false;
+    }
+
+    // Unlike isSingleElementStruct(), trailing padding is allowed.
+    // An 8-byte aligned struct s { float f; } is passed as a double.
+    return Found;
+  }
+
+  return false;
+}
+
+llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+                                       CodeGenFunction &CGF) const {
+  // Assume that va_list type is correct; should be pointer to LLVM type:
+  // struct {
+  //   i64 __gpr;
+  //   i64 __fpr;
+  //   i8 *__overflow_arg_area;
+  //   i8 *__reg_save_area;
+  // };
+
+  // Every argument occupies 8 bytes and is passed by preference in either
+  // GPRs or FPRs.
+  Ty = CGF.getContext().getCanonicalType(Ty);
+  ABIArgInfo AI = classifyArgumentType(Ty);
+  bool InFPRs = isFPArgumentType(Ty);
+
+  llvm::Type *APTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty));
+  bool IsIndirect = AI.isIndirect();
+  unsigned UnpaddedBitSize;
+  if (IsIndirect) {
+    APTy = llvm::PointerType::getUnqual(APTy);
+    UnpaddedBitSize = 64;
+  } else
+    UnpaddedBitSize = getContext().getTypeSize(Ty);
+  unsigned PaddedBitSize = 64;
+  assert((UnpaddedBitSize <= PaddedBitSize) && "Invalid argument size.");
+
+  unsigned PaddedSize = PaddedBitSize / 8;
+  unsigned Padding = (PaddedBitSize - UnpaddedBitSize) / 8;
+
+  unsigned MaxRegs, RegCountField, RegSaveIndex, RegPadding;
+  if (InFPRs) {
+    MaxRegs = 4; // Maximum of 4 FPR arguments
+    RegCountField = 1; // __fpr
+    RegSaveIndex = 16; // save offset for f0
+    RegPadding = 0; // floats are passed in the high bits of an FPR
+  } else {
+    MaxRegs = 5; // Maximum of 5 GPR arguments
+    RegCountField = 0; // __gpr
+    RegSaveIndex = 2; // save offset for r2
+    RegPadding = Padding; // values are passed in the low bits of a GPR
+  }
+
+  llvm::Value *RegCountPtr =
+    CGF.Builder.CreateStructGEP(VAListAddr, RegCountField, "reg_count_ptr");
+  llvm::Value *RegCount = CGF.Builder.CreateLoad(RegCountPtr, "reg_count");
+  llvm::Type *IndexTy = RegCount->getType();
+  llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs);
+  llvm::Value *InRegs = CGF.Builder.CreateICmpULT(RegCount, MaxRegsV,
+						  "fits_in_regs");
+
+  llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
+  llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem");
+  llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
+  CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock);
+
+  // Emit code to load the value if it was passed in registers.
+  CGF.EmitBlock(InRegBlock);
+
+  // Work out the address of an argument register.
+  llvm::Value *PaddedSizeV = llvm::ConstantInt::get(IndexTy, PaddedSize);
+  llvm::Value *ScaledRegCount =
+    CGF.Builder.CreateMul(RegCount, PaddedSizeV, "scaled_reg_count");
+  llvm::Value *RegBase =
+    llvm::ConstantInt::get(IndexTy, RegSaveIndex * PaddedSize + RegPadding);
+  llvm::Value *RegOffset =
+    CGF.Builder.CreateAdd(ScaledRegCount, RegBase, "reg_offset");
+  llvm::Value *RegSaveAreaPtr =
+    CGF.Builder.CreateStructGEP(VAListAddr, 3, "reg_save_area_ptr");
+  llvm::Value *RegSaveArea =
+    CGF.Builder.CreateLoad(RegSaveAreaPtr, "reg_save_area");
+  llvm::Value *RawRegAddr =
+    CGF.Builder.CreateGEP(RegSaveArea, RegOffset, "raw_reg_addr");
+  llvm::Value *RegAddr =
+    CGF.Builder.CreateBitCast(RawRegAddr, APTy, "reg_addr");
+
+  // Update the register count
+  llvm::Value *One = llvm::ConstantInt::get(IndexTy, 1);
+  llvm::Value *NewRegCount =
+    CGF.Builder.CreateAdd(RegCount, One, "reg_count");
+  CGF.Builder.CreateStore(NewRegCount, RegCountPtr);
+  CGF.EmitBranch(ContBlock);
+
+  // Emit code to load the value if it was passed in memory.
+  CGF.EmitBlock(InMemBlock);
+
+  // Work out the address of a stack argument.
+  llvm::Value *OverflowArgAreaPtr =
+    CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_ptr");
+  llvm::Value *OverflowArgArea =
+    CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area");
+  llvm::Value *PaddingV = llvm::ConstantInt::get(IndexTy, Padding);
+  llvm::Value *RawMemAddr =
+    CGF.Builder.CreateGEP(OverflowArgArea, PaddingV, "raw_mem_addr");
+  llvm::Value *MemAddr =
+    CGF.Builder.CreateBitCast(RawMemAddr, APTy, "mem_addr");
+
+  // Update overflow_arg_area_ptr pointer
+  llvm::Value *NewOverflowArgArea =
+    CGF.Builder.CreateGEP(OverflowArgArea, PaddedSizeV, "overflow_arg_area");
+  CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr);
+  CGF.EmitBranch(ContBlock);
+
+  // Return the appropriate result.
+  CGF.EmitBlock(ContBlock);
+  llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(APTy, 2, "va_arg.addr");
+  ResAddr->addIncoming(RegAddr, InRegBlock);
+  ResAddr->addIncoming(MemAddr, InMemBlock);
+
+  if (IsIndirect)
+    return CGF.Builder.CreateLoad(ResAddr, "indirect_arg");
+
+  return ResAddr;
+}
+
+
+ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
+  if (RetTy->isVoidType())
+    return ABIArgInfo::getIgnore();
+  if (isCompoundType(RetTy) || getContext().getTypeSize(RetTy) > 64)
+    return ABIArgInfo::getIndirect(0);
+  return (isPromotableIntegerType(RetTy) ?
+          ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
+  // Handle the generic C++ ABI.
+  if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT))
+    return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
+
+  // Integers and enums are extended to full register width.
+  if (isPromotableIntegerType(Ty))
+    return ABIArgInfo::getExtend();
+
+  // Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly.
+  uint64_t Size = getContext().getTypeSize(Ty);
+  if (Size != 8 && Size != 16 && Size != 32 && Size != 64)
+    return ABIArgInfo::getIndirect(0);
+
+  // Handle small structures.
+  if (const RecordType *RT = Ty->getAs<RecordType>()) {
+    // Structures with flexible arrays have variable length, so really
+    // fail the size test above.
+    const RecordDecl *RD = RT->getDecl();
+    if (RD->hasFlexibleArrayMember())
+      return ABIArgInfo::getIndirect(0);
+
+    // The structure is passed as an unextended integer, a float, or a double.
+    llvm::Type *PassTy;
+    if (isFPArgumentType(Ty)) {
+      assert(Size == 32 || Size == 64);
+      if (Size == 32)
+        PassTy = llvm::Type::getFloatTy(getVMContext());
+      else
+        PassTy = llvm::Type::getDoubleTy(getVMContext());
+    } else
+      PassTy = llvm::IntegerType::get(getVMContext(), Size);
+    return ABIArgInfo::getDirect(PassTy);
+  }
+
+  // Non-structure compounds are passed indirectly.
+  if (isCompoundType(Ty))
+    return ABIArgInfo::getIndirect(0);
+
+  return ABIArgInfo::getDirect(0);
+}
+
+//===----------------------------------------------------------------------===//
 // MBlaze ABI Implementation
 //===----------------------------------------------------------------------===//
 
@@ -4860,6 +5147,9 @@
   case llvm::Triple::msp430:
     return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types));
 
+  case llvm::Triple::systemz:
+    return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types));
+
   case llvm::Triple::tce:
     return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types));
 
Index: lib/Driver/ToolChains.cpp
===================================================================
--- lib/Driver/ToolChains.cpp
+++ lib/Driver/ToolChains.cpp
@@ -1146,6 +1146,15 @@
     "ppc64-redhat-linux"
   };
 
+  static const char *const SystemZLibDirs[] = { "/lib64", "/lib" };
+  static const char *const SystemZTriples[] = {
+    "s390x-linux-gnu",
+    "s390x-unknown-linux-gnu",
+    "s390x-ibm-linux-gnu",
+    "s390x-suse-linux",
+    "s390x-redhat-linux"
+  };
+
   switch (TargetTriple.getArch()) {
   case llvm::Triple::aarch64:
     LibDirs.append(AArch64LibDirs, AArch64LibDirs
@@ -1246,6 +1255,12 @@
     MultiarchTripleAliases.append(
       PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
     break;
+  case llvm::Triple::systemz:
+    LibDirs.append(
+      SystemZLibDirs, SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs));
+    TripleAliases.append(
+      SystemZTriples, SystemZTriples + llvm::array_lengthof(SystemZTriples));
+    break;
 
   default:
     // By default, just rely on the standard lib directories and the original
@@ -1349,7 +1364,8 @@
   }
 
   if (TargetArch == llvm::Triple::x86_64 ||
-      TargetArch == llvm::Triple::ppc64)
+      TargetArch == llvm::Triple::ppc64 ||
+      TargetArch == llvm::Triple::systemz)
     Suffix = "/64";
   else
     Suffix = "/32";
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -544,6 +544,9 @@
     if (Triple.isOSDarwin())
       return true;
     return false;
+
+  case llvm::Triple::systemz:
+    return false;
   }
 }
 
@@ -5775,6 +5778,9 @@
          LastPICArg->getOption().matches(options::OPT_fpie))) {
       CmdArgs.push_back("-KPIC");
     }
+  } else if (getToolChain().getArch() == llvm::Triple::systemz) {
+    // At the moment we always produce z10 code.
+    CmdArgs.push_back("-march=z10");
   }
 
   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5906,6 +5912,8 @@
     else
       CmdArgs.push_back("elf64ltsmip");
   }
+  else if (ToolChain.getArch() == llvm::Triple::systemz)
+    CmdArgs.push_back("elf64_s390");
   else
     CmdArgs.push_back("elf_x86_64");
 
@@ -5952,7 +5960,8 @@
     }
     else if (ToolChain.getArch() == llvm::Triple::ppc)
       CmdArgs.push_back("/lib/ld.so.1");
-    else if (ToolChain.getArch() == llvm::Triple::ppc64)
+    else if (ToolChain.getArch() == llvm::Triple::ppc64 ||
+	     ToolChain.getArch() == llvm::Triple::systemz)
       CmdArgs.push_back("/lib64/ld64.so.1");
     else
       CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2");
Index: test/CodeGen/c-strings.c
===================================================================
--- test/CodeGen/c-strings.c
+++ test/CodeGen/c-strings.c
@@ -3,12 +3,19 @@
 // Should be 3 hello strings, two global (of different sizes), the rest are
 // shared.
 
+// CHECK: @align = global i8 [[ALIGN:[0-9]+]]
 // CHECK: @.str = private unnamed_addr constant [6 x i8] c"hello\00"
 // CHECK: @f1.x = internal global i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0)
-// CHECK: @f2.x = internal global [6 x i8] c"hello\00", align 1
-// CHECK: @f3.x = internal global [8 x i8] c"hello\00\00\00", align 1
+// CHECK: @f2.x = internal global [6 x i8] c"hello\00", align [[ALIGN]]
+// CHECK: @f3.x = internal global [8 x i8] c"hello\00\00\00", align [[ALIGN]]
 // CHECK: @f4.x = internal global %struct.s { i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0) }
-// CHECK: @x = global [3 x i8] c"ola", align 1
+// CHECK: @x = global [3 x i8] c"ola", align [[ALIGN]]
+
+#if defined(__s390x__)
+unsigned char align = 2;
+#else
+unsigned char align = 1;
+#endif
 
 void bar(const char *);
 
Index: test/CodeGen/mult-alt-generic.c
===================================================================
--- test/CodeGen/mult-alt-generic.c
+++ test/CodeGen/mult-alt-generic.c
@@ -6,6 +6,7 @@
 // RUN: %clang_cc1 -triple mipsel %s -emit-llvm -o - | FileCheck %s
 // RUN: %clang_cc1 -triple powerpc %s -emit-llvm -o - | FileCheck %s
 // RUN: %clang_cc1 -triple powerpc64 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple s390x %s -emit-llvm -o - | FileCheck %s
 // RUN: %clang_cc1 -triple sparc %s -emit-llvm -o - | FileCheck %s
 // RUN: %clang_cc1 -triple sparcv9 %s -emit-llvm -o - | FileCheck %s
 // RUN: %clang_cc1 -triple thumb %s -emit-llvm -o - | FileCheck %s
Index: test/Preprocessor/init.c
===================================================================
--- test/Preprocessor/init.c
+++ test/Preprocessor/init.c
@@ -2163,6 +2163,98 @@
 // PPC-LINUX:#define __powerpc__ 1
 // PPC-LINUX:#define __ppc__ 1
 //
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=s390x-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix S390X %s
+//
+// S390X:#define __CHAR16_TYPE__ unsigned short
+// S390X:#define __CHAR32_TYPE__ unsigned int
+// S390X:#define __CHAR_BIT__ 8
+// S390X:#define __CHAR_UNSIGNED__ 1
+// S390X:#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
+// S390X:#define __DBL_DIG__ 15
+// S390X:#define __DBL_EPSILON__ 2.2204460492503131e-16
+// S390X:#define __DBL_HAS_DENORM__ 1
+// S390X:#define __DBL_HAS_INFINITY__ 1
+// S390X:#define __DBL_HAS_QUIET_NAN__ 1
+// S390X:#define __DBL_MANT_DIG__ 53
+// S390X:#define __DBL_MAX_10_EXP__ 308
+// S390X:#define __DBL_MAX_EXP__ 1024
+// S390X:#define __DBL_MAX__ 1.7976931348623157e+308
+// S390X:#define __DBL_MIN_10_EXP__ (-307)
+// S390X:#define __DBL_MIN_EXP__ (-1021)
+// S390X:#define __DBL_MIN__ 2.2250738585072014e-308
+// S390X:#define __DECIMAL_DIG__ 36
+// S390X:#define __FLT_DENORM_MIN__ 1.40129846e-45F
+// S390X:#define __FLT_DIG__ 6
+// S390X:#define __FLT_EPSILON__ 1.19209290e-7F
+// S390X:#define __FLT_EVAL_METHOD__ 0
+// S390X:#define __FLT_HAS_DENORM__ 1
+// S390X:#define __FLT_HAS_INFINITY__ 1
+// S390X:#define __FLT_HAS_QUIET_NAN__ 1
+// S390X:#define __FLT_MANT_DIG__ 24
+// S390X:#define __FLT_MAX_10_EXP__ 38
+// S390X:#define __FLT_MAX_EXP__ 128
+// S390X:#define __FLT_MAX__ 3.40282347e+38F
+// S390X:#define __FLT_MIN_10_EXP__ (-37)
+// S390X:#define __FLT_MIN_EXP__ (-125)
+// S390X:#define __FLT_MIN__ 1.17549435e-38F
+// S390X:#define __FLT_RADIX__ 2
+// S390X:#define __INT16_TYPE__ short
+// S390X:#define __INT32_TYPE__ int
+// S390X:#define __INT64_C_SUFFIX__ L
+// S390X:#define __INT64_TYPE__ long long int
+// S390X:#define __INT8_TYPE__ char
+// S390X:#define __INTMAX_MAX__ 9223372036854775807LL
+// S390X:#define __INTMAX_TYPE__ long long int
+// S390X:#define __INTMAX_WIDTH__ 64
+// S390X:#define __INTPTR_TYPE__ long int
+// S390X:#define __INTPTR_WIDTH__ 64
+// S390X:#define __INT_MAX__ 2147483647
+// S390X:#define __LDBL_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966L
+// S390X:#define __LDBL_DIG__ 33
+// S390X:#define __LDBL_EPSILON__ 1.92592994438723585305597794258492732e-34L
+// S390X:#define __LDBL_HAS_DENORM__ 1
+// S390X:#define __LDBL_HAS_INFINITY__ 1
+// S390X:#define __LDBL_HAS_QUIET_NAN__ 1
+// S390X:#define __LDBL_MANT_DIG__ 113
+// S390X:#define __LDBL_MAX_10_EXP__ 4932
+// S390X:#define __LDBL_MAX_EXP__ 16384
+// S390X:#define __LDBL_MAX__ 1.18973149535723176508575932662800702e+4932L
+// S390X:#define __LDBL_MIN_10_EXP__ (-4931)
+// S390X:#define __LDBL_MIN_EXP__ (-16381)
+// S390X:#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L
+// S390X:#define __LONG_LONG_MAX__ 9223372036854775807LL
+// S390X:#define __LONG_MAX__ 9223372036854775807L
+// S390X:#define __NO_INLINE__ 1
+// S390X:#define __POINTER_WIDTH__ 64
+// S390X:#define __PTRDIFF_TYPE__ long int
+// S390X:#define __PTRDIFF_WIDTH__ 64
+// S390X:#define __SCHAR_MAX__ 127
+// S390X:#define __SHRT_MAX__ 32767
+// S390X:#define __SIG_ATOMIC_WIDTH__ 32
+// S390X:#define __SIZEOF_DOUBLE__ 8
+// S390X:#define __SIZEOF_FLOAT__ 4
+// S390X:#define __SIZEOF_INT__ 4
+// S390X:#define __SIZEOF_LONG_DOUBLE__ 16
+// S390X:#define __SIZEOF_LONG_LONG__ 8
+// S390X:#define __SIZEOF_LONG__ 8
+// S390X:#define __SIZEOF_POINTER__ 8
+// S390X:#define __SIZEOF_PTRDIFF_T__ 8
+// S390X:#define __SIZEOF_SHORT__ 2
+// S390X:#define __SIZEOF_SIZE_T__ 8
+// S390X:#define __SIZEOF_WCHAR_T__ 4
+// S390X:#define __SIZEOF_WINT_T__ 4
+// S390X:#define __SIZE_TYPE__ long unsigned int
+// S390X:#define __SIZE_WIDTH__ 64
+// S390X:#define __UINTMAX_TYPE__ long long unsigned int
+// S390X:#define __USER_LABEL_PREFIX__ _
+// S390X:#define __WCHAR_MAX__ 2147483647
+// S390X:#define __WCHAR_TYPE__ int
+// S390X:#define __WCHAR_WIDTH__ 32
+// S390X:#define __WINT_TYPE__ int
+// S390X:#define __WINT_WIDTH__ 32
+// S390X:#define __s390__ 1
+// S390X:#define __s390x__ 1
+//
 // RUN: %clang_cc1 -E -dM -ffreestanding -triple=sparc-none-none < /dev/null | FileCheck -check-prefix SPARC %s
 //
 // SPARC-NOT:#define _LP64
Index: test/Preprocessor/stdint.c
===================================================================
--- test/Preprocessor/stdint.c
+++ test/Preprocessor/stdint.c
@@ -528,6 +528,113 @@
 // PPC:INTMAX_C_(0) 0LL
 // PPC:UINTMAX_C_(0) 0ULL
 //
+// RUN: %clang_cc1 -E -ffreestanding -triple=s390x-none-none %s | FileCheck -check-prefix S390X %s
+//
+// S390X:typedef signed long long int int64_t;
+// S390X:typedef unsigned long long int uint64_t;
+// S390X:typedef int64_t int_least64_t;
+// S390X:typedef uint64_t uint_least64_t;
+// S390X:typedef int64_t int_fast64_t;
+// S390X:typedef uint64_t uint_fast64_t;
+//
+// S390X:typedef signed int int32_t;
+// S390X:typedef unsigned int uint32_t;
+// S390X:typedef int32_t int_least32_t;
+// S390X:typedef uint32_t uint_least32_t;
+// S390X:typedef int32_t int_fast32_t;
+// S390X:typedef uint32_t uint_fast32_t;
+//
+// S390X:typedef signed short int16_t;
+// S390X:typedef unsigned short uint16_t;
+// S390X:typedef int16_t int_least16_t;
+// S390X:typedef uint16_t uint_least16_t;
+// S390X:typedef int16_t int_fast16_t;
+// S390X:typedef uint16_t uint_fast16_t;
+//
+// S390X:typedef signed char int8_t;
+// S390X:typedef unsigned char uint8_t;
+// S390X:typedef int8_t int_least8_t;
+// S390X:typedef uint8_t uint_least8_t;
+// S390X:typedef int8_t int_fast8_t;
+// S390X:typedef uint8_t uint_fast8_t;
+//
+// S390X:typedef int64_t intptr_t;
+// S390X:typedef uint64_t uintptr_t;
+//
+// S390X:typedef long long int intmax_t;
+// S390X:typedef long long unsigned int uintmax_t;
+//
+// S390X:INT8_MAX_ 127
+// S390X:INT8_MIN_ (-127 -1)
+// S390X:UINT8_MAX_ 255
+// S390X:INT_LEAST8_MIN_ (-127 -1)
+// S390X:INT_LEAST8_MAX_ 127
+// S390X:UINT_LEAST8_MAX_ 255
+// S390X:INT_FAST8_MIN_ (-127 -1)
+// S390X:INT_FAST8_MAX_ 127
+// S390X:UINT_FAST8_MAX_ 255
+//
+// S390X:INT16_MAX_ 32767
+// S390X:INT16_MIN_ (-32767 -1)
+// S390X:UINT16_MAX_ 65535
+// S390X:INT_LEAST16_MIN_ (-32767 -1)
+// S390X:INT_LEAST16_MAX_ 32767
+// S390X:UINT_LEAST16_MAX_ 65535
+// S390X:INT_FAST16_MIN_ (-32767 -1)
+// S390X:INT_FAST16_MAX_ 32767
+// S390X:UINT_FAST16_MAX_ 65535
+//
+// S390X:INT32_MAX_ 2147483647
+// S390X:INT32_MIN_ (-2147483647 -1)
+// S390X:UINT32_MAX_ 4294967295U
+// S390X:INT_LEAST32_MIN_ (-2147483647 -1)
+// S390X:INT_LEAST32_MAX_ 2147483647
+// S390X:UINT_LEAST32_MAX_ 4294967295U
+// S390X:INT_FAST32_MIN_ (-2147483647 -1)
+// S390X:INT_FAST32_MAX_ 2147483647
+// S390X:UINT_FAST32_MAX_ 4294967295U
+//
+// S390X:INT64_MAX_ 9223372036854775807L
+// S390X:INT64_MIN_ (-9223372036854775807LL -1)
+// S390X:UINT64_MAX_ 18446744073709551615UL
+// S390X:INT_LEAST64_MIN_ (-9223372036854775807LL -1)
+// S390X:INT_LEAST64_MAX_ 9223372036854775807L
+// S390X:UINT_LEAST64_MAX_ 18446744073709551615UL
+// S390X:INT_FAST64_MIN_ (-9223372036854775807LL -1)
+// S390X:INT_FAST64_MAX_ 9223372036854775807L
+// S390X:UINT_FAST64_MAX_ 18446744073709551615UL
+//
+// S390X:INTPTR_MIN_ (-9223372036854775807LL -1)
+// S390X:INTPTR_MAX_ 9223372036854775807L
+// S390X:UINTPTR_MAX_ 18446744073709551615UL
+// S390X:PTRDIFF_MIN_ (-9223372036854775807LL -1)
+// S390X:PTRDIFF_MAX_ 9223372036854775807L
+// S390X:SIZE_MAX_ 18446744073709551615UL
+//
+// S390X:INTMAX_MIN_ (-9223372036854775807LL -1)
+// S390X:INTMAX_MAX_ 9223372036854775807L
+// S390X:UINTMAX_MAX_ 18446744073709551615UL
+//
+// S390X:SIG_ATOMIC_MIN_ (-2147483647 -1)
+// S390X:SIG_ATOMIC_MAX_ 2147483647
+// S390X:WINT_MIN_ (-2147483647 -1)
+// S390X:WINT_MAX_ 2147483647
+//
+// S390X:WCHAR_MAX_ 2147483647
+// S390X:WCHAR_MIN_ (-2147483647 -1)
+//
+// S390X:INT8_C_(0) 0
+// S390X:UINT8_C_(0) 0U
+// S390X:INT16_C_(0) 0
+// S390X:UINT16_C_(0) 0U
+// S390X:INT32_C_(0) 0
+// S390X:UINT32_C_(0) 0U
+// S390X:INT64_C_(0) 0L
+// S390X:UINT64_C_(0) 0UL
+//
+// S390X:INTMAX_C_(0) 0L
+// S390X:UINTMAX_C_(0) 0UL
+//
 // RUN: %clang_cc1 -E -ffreestanding -triple=sparc-none-none %s | FileCheck -check-prefix SPARC %s
 //
 // SPARC:typedef signed long long int int64_t;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to