From b8409215523e5478b8b0aa9cdcd10038cf7651fe Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Mon, 6 May 2013 16:26:41 +0000 Subject: [PATCH] Add SystemZ support This patch then adds all the usual platform-specific pieces for SystemZ: driver support, basic target info, register names and constraints, ABI info and vararg support. It also adds new tests to verify pre-defined macros and inline asm, and updates a test for the minimum alignment change. This version of the patch incorporates feedback from reviews by Eric Christopher and John McCall. Thanks to all reviewers! Patch by Richard Sandiford. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181211 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/TargetInfo.h | 11 +- lib/AST/ASTContext.cpp | 76 ++++++++ lib/Basic/Targets.cpp | 102 +++++++++++ lib/CodeGen/TargetInfo.cpp | 290 ++++++++++++++++++++++++++++++ lib/Driver/ToolChains.cpp | 18 +- lib/Driver/Tools.cpp | 11 +- test/CodeGen/c-strings.c | 13 +- test/CodeGen/mult-alt-generic.c | 1 + test/CodeGen/systemz-inline-asm.c | 131 ++++++++++++++ test/Preprocessor/init.c | 92 ++++++++++ test/Preprocessor/stdint.c | 107 +++++++++++ 11 files changed, 846 insertions(+), 6 deletions(-) create mode 100644 test/CodeGen/systemz-inline-asm.c diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 21325fac36..49b26ac8e3 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -157,7 +157,16 @@ public: /// __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: diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8d40a6a299..2a405271b6 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5980,6 +5980,80 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { 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(*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(*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(*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) { @@ -5997,6 +6071,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context, return CreatePNaClABIBuiltinVaListDecl(Context); case TargetInfo::AAPCSABIBuiltinVaList: return CreateAAPCSABIBuiltinVaListDecl(Context); + case TargetInfo::SystemZBuiltinVaList: + return CreateSystemZBuiltinVaListDecl(Context); } llvm_unreachable("Unhandled __builtin_va_list type kind"); diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index cabdffa68c..96b12bac1f 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -4314,6 +4314,100 @@ public: }; } // 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 'd': // Data register (equivalent to 'r') + case 'f': // Floating-point register + 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 '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[]; @@ -5281,6 +5375,14 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new SparcV9TargetInfo(T); } + case llvm::Triple::systemz: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo(T); + default: + return new SystemZTargetInfo(T); + } + case llvm::Triple::tce: return new TCETargetInfo(T); diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 83d1f6d8b5..32b27b3172 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -4116,6 +4116,293 @@ void NVPTXTargetCodeGenInfo::addKernelMetadata(llvm::Function *F) { } +//===----------------------------------------------------------------------===// +// 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()) + 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()) + 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()) + 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(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()) { + // 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 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { 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)); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 1ca2a34bfe..fffba0e4e5 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -1146,6 +1146,15 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( "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 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( 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 @@ static bool findTargetMultiarchSuffix(std::string &Suffix, } if (TargetArch == llvm::Triple::x86_64 || - TargetArch == llvm::Triple::ppc64) + TargetArch == llvm::Triple::ppc64 || + TargetArch == llvm::Triple::systemz) Suffix = "/64"; else Suffix = "/32"; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index ef4b005efc..47d12e1e3b 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -545,6 +545,9 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { if (Triple.isOSDarwin()) return true; return false; + + case llvm::Triple::systemz: + return false; } } @@ -5820,6 +5823,9 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, 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, @@ -5951,6 +5957,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("elf64ltsmip"); } + else if (ToolChain.getArch() == llvm::Triple::systemz) + CmdArgs.push_back("elf64_s390"); else CmdArgs.push_back("elf_x86_64"); @@ -5997,7 +6005,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, } 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"); diff --git a/test/CodeGen/c-strings.c b/test/CodeGen/c-strings.c index 1021010a6d..60a6b01912 100644 --- a/test/CodeGen/c-strings.c +++ b/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 *); diff --git a/test/CodeGen/mult-alt-generic.c b/test/CodeGen/mult-alt-generic.c index cbe7898ad8..111679e3a9 100644 --- a/test/CodeGen/mult-alt-generic.c +++ b/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 diff --git a/test/CodeGen/systemz-inline-asm.c b/test/CodeGen/systemz-inline-asm.c new file mode 100644 index 0000000000..8e5854f1bb --- /dev/null +++ b/test/CodeGen/systemz-inline-asm.c @@ -0,0 +1,131 @@ +// RUN: %clang_cc1 -triple s390x-linux-gnu -O2 -emit-llvm -o - %s | FileCheck %s + +unsigned int gi; +unsigned long gl; + +void test_store_m(unsigned int i) { + asm("st %1, %0" : "=m" (gi) : "r" (i)); +// CHECK: define void @test_store_m(i32 zeroext %i) +// CHECK: call void asm "st $1, $0", "=*m,r"(i32* @gi, i32 %i) +} + +void test_store_Q(unsigned int i) { + asm("st %1, %0" : "=Q" (gi) : "r" (i)); +// CHECK: define void @test_store_Q(i32 zeroext %i) +// CHECK: call void asm "st $1, $0", "=*Q,r"(i32* @gi, i32 %i) +} + +void test_store_R(unsigned int i) { + asm("st %1, %0" : "=R" (gi) : "r" (i)); +// CHECK: define void @test_store_R(i32 zeroext %i) +// CHECK: call void asm "st $1, $0", "=*R,r"(i32* @gi, i32 %i) +} + +void test_store_S(unsigned int i) { + asm("st %1, %0" : "=S" (gi) : "r" (i)); +// CHECK: define void @test_store_S(i32 zeroext %i) +// CHECK: call void asm "st $1, $0", "=*S,r"(i32* @gi, i32 %i) +} + +void test_store_T(unsigned int i) { + asm("st %1, %0" : "=T" (gi) : "r" (i)); +// CHECK: define void @test_store_T(i32 zeroext %i) +// CHECK: call void asm "st $1, $0", "=*T,r"(i32* @gi, i32 %i) +} + +int test_load_m() { + unsigned int i; + asm("l %0, %1" : "=r" (i) : "m" (gi)); + return i; +// CHECK: define signext i32 @test_load_m() +// CHECK: call i32 asm "l $0, $1", "=r,*m"(i32* @gi) +} + +int test_load_Q() { + unsigned int i; + asm("l %0, %1" : "=r" (i) : "Q" (gi)); + return i; +// CHECK: define signext i32 @test_load_Q() +// CHECK: call i32 asm "l $0, $1", "=r,*Q"(i32* @gi) +} + +int test_load_R() { + unsigned int i; + asm("l %0, %1" : "=r" (i) : "R" (gi)); + return i; +// CHECK: define signext i32 @test_load_R() +// CHECK: call i32 asm "l $0, $1", "=r,*R"(i32* @gi) +} + +int test_load_S() { + unsigned int i; + asm("l %0, %1" : "=r" (i) : "S" (gi)); + return i; +// CHECK: define signext i32 @test_load_S() +// CHECK: call i32 asm "l $0, $1", "=r,*S"(i32* @gi) +} + +int test_load_T() { + unsigned int i; + asm("l %0, %1" : "=r" (i) : "T" (gi)); + return i; +// CHECK: define signext i32 @test_load_T() +// CHECK: call i32 asm "l $0, $1", "=r,*T"(i32* @gi) +} + +void test_mI(unsigned char *c) { + asm volatile("cli %0, %1" :: "Q" (*c), "I" (100)); +// CHECK: define void @test_mI(i8* %c) +// CHECK: call void asm sideeffect "cli $0, $1", "*Q,I"(i8* %c, i32 100) +} + +unsigned int test_dJa(unsigned int i, unsigned int j) { + asm("sll %0, %2(%3)" : "=d" (i) : "0" (i), "J" (1000), "a" (j)); + return i; +// CHECK: define zeroext i32 @test_dJa(i32 zeroext %i, i32 zeroext %j) +// CHECK: call i32 asm "sll $0, $2($3)", "=d,0,J,a"(i32 %i, i32 1000, i32 %j) +} + +unsigned long test_rK(unsigned long i) { + asm("aghi %0, %2" : "=r" (i) : "0" (i), "K" (-30000)); + return i; +// CHECK: define i64 @test_rK(i64 %i) +// CHECK: call i64 asm "aghi $0, $2", "=r,0,K"(i64 %i, i32 -30000) +} + +unsigned long test_rL(unsigned long i) { + asm("sllg %0, %1, %2" : "=r" (i) : "r" (i), "L" (500000)); + return i; +// CHECK: define i64 @test_rL(i64 %i) +// CHECK: call i64 asm "sllg $0, $1, $2", "=r,r,L"(i64 %i, i32 500000) +} + +void test_M() { + asm volatile("#FOO %0" :: "M"(0x7fffffff)); +// CHECK: define void @test_M() +// CHECK: call void asm sideeffect "#FOO $0", "M"(i32 2147483647) +} + +float test_f32(float f, float g) { + asm("aebr %0, %2" : "=f" (f) : "0" (f), "f" (g)); + return f; +// CHECK: define float @test_f32(float %f, float %g) +// CHECK: call float asm "aebr $0, $2", "=f,0,f"(float %f, float %g) +} + +double test_f64(double f, double g) { + asm("adbr %0, %2" : "=f" (f) : "0" (f), "f" (g)); + return f; +// CHECK: define double @test_f64(double %f, double %g) +// CHECK: call double asm "adbr $0, $2", "=f,0,f"(double %f, double %g) +} + +long double test_f128(long double f, long double g) { + asm("axbr %0, %2" : "=f" (f) : "0" (f), "f" (g)); + return f; +// CHECK: define void @test_f128(fp128* noalias nocapture sret [[DEST:%.*]], fp128* byval nocapture, fp128* byval nocapture) +// CHECK: %f = load fp128* %0 +// CHECK: %g = load fp128* %1 +// CHECK: [[RESULT:%.*]] = tail call fp128 asm "axbr $0, $2", "=f,0,f"(fp128 %f, fp128 %g) +// CHECK: store fp128 [[RESULT]], fp128* [[DEST]] +} diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c index b69c76ce1b..95f169fb9b 100644 --- a/test/Preprocessor/init.c +++ b/test/Preprocessor/init.c @@ -2177,6 +2177,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 diff --git a/test/Preprocessor/stdint.c b/test/Preprocessor/stdint.c index 70c106bf79..c3be05d97c 100644 --- a/test/Preprocessor/stdint.c +++ b/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; -- 2.40.0