diff --git a/debian/changelog b/debian/changelog index 2a97a001..0285c4b0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -52,10 +52,18 @@ llvm-toolchain-snapshot (1:11~++20200123111717+04fd2041561-1~exp1) experimental; -- Sylvestre Ledru Thu, 23 Jan 2020 14:52:30 +0100 +llvm-toolchain-10 (1:10.0.1-1~++20200417104440+92d5c1be9ee) UNRELEASED; urgency=medium + + * prepare version 10.0.1 (go back to 10.0.0-5 for debian if needed) + * Enable LLVM_ENABLE_DUMP (Closes: #956966) + + -- Sylvestre Ledru Fri, 17 Apr 2020 23:24:13 +0200 + llvm-toolchain-10 (1:10.0.0-4) unstable; urgency=medium * Also ship polly libs in libclang-common-10-dev. Fixes bug #44870 (upstream) + * move risc patches into their own directory -- Sylvestre Ledru Fri, 10 Apr 2020 10:27:41 +0200 diff --git a/debian/patches/clang-riscv64-hf-abi.diff b/debian/patches/clang-riscv64-hf-abi.diff deleted file mode 100644 index 81b87bdf..00000000 --- a/debian/patches/clang-riscv64-hf-abi.diff +++ /dev/null @@ -1,1753 +0,0 @@ -commit e078967adf4f4f84da52b8d739aea75ed2ce5f16 -Author: Alex Bradbury -Date: Thu Jul 18 18:29:59 2019 +0000 - - [RISCV] Hard float ABI support - - The RISC-V hard float calling convention requires the frontend to: - - * Detect cases where, once "flattened", a struct can be passed using - int+fp or fp+fp registers under the hard float ABI and coerce to the - appropriate type(s) - * Track usage of GPRs and FPRs in order to gate the above, and to - determine when signext/zeroext attributes must be added to integer - scalars - - This patch attempts to do this in compliance with the documented ABI, - and uses ABIArgInfo::CoerceAndExpand in order to do this. @rjmccall, as - author of that code I've tagged you as reviewer for initial feedback on - my usage. - - Note that a previous version of the ABI indicated that when passing an - int+fp struct using a GPR+FPR, the int would need to be sign or - zero-extended appropriately. GCC never did this and the ABI was changed, - which makes life easier as ABIArgInfo::CoerceAndExpand can't currently - handle sign/zero-extension attributes. - - Re-landed after backing out 366450 due to missed hunks. - - Differential Revision: https://reviews.llvm.org/D60456 - - llvm-svn: 366480 - -diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp -index f800bb0b25d..58272d14abd 100644 ---- a/clang/lib/Basic/Targets/RISCV.cpp -+++ b/clang/lib/Basic/Targets/RISCV.cpp -@@ -65,9 +65,18 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, - Builder.defineMacro("__riscv"); - bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64; - Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32"); -- // TODO: modify when more code models and ABIs are supported. -+ // TODO: modify when more code models are supported. - Builder.defineMacro("__riscv_cmodel_medlow"); -- Builder.defineMacro("__riscv_float_abi_soft"); -+ -+ StringRef ABIName = getABI(); -+ if (ABIName == "ilp32f" || ABIName == "lp64f") -+ Builder.defineMacro("__riscv_float_abi_single"); -+ else if (ABIName == "ilp32d" || ABIName == "lp64d") -+ Builder.defineMacro("__riscv_float_abi_double"); -+ else if (ABIName == "ilp32e") -+ Builder.defineMacro("__riscv_abi_rve"); -+ else -+ Builder.defineMacro("__riscv_float_abi_soft"); - - if (HasM) { - Builder.defineMacro("__riscv_mul"); -diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h -index bc814b79ce5..ce193feaeb9 100644 ---- a/clang/lib/Basic/Targets/RISCV.h -+++ b/clang/lib/Basic/Targets/RISCV.h -@@ -87,8 +87,7 @@ public: - } - - bool setABI(const std::string &Name) override { -- // TODO: support ilp32f and ilp32d ABIs. -- if (Name == "ilp32") { -+ if (Name == "ilp32" || Name == "ilp32f" || Name == "ilp32d") { - ABI = Name; - return true; - } -@@ -105,8 +104,7 @@ public: - } - - bool setABI(const std::string &Name) override { -- // TODO: support lp64f and lp64d ABIs. -- if (Name == "lp64") { -+ if (Name == "lp64" || Name == "lp64f" || Name == "lp64d") { - ABI = Name; - return true; - } -diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp -index 5da988fb8a3..1e1038dbfe9 100644 ---- a/clang/lib/CodeGen/TargetInfo.cpp -+++ b/clang/lib/CodeGen/TargetInfo.cpp -@@ -9188,25 +9188,45 @@ static bool getTypeString(SmallStringEnc &Enc, const Decl *D, - namespace { - class RISCVABIInfo : public DefaultABIInfo { - private: -- unsigned XLen; // Size of the integer ('x') registers in bits. -+ // Size of the integer ('x') registers in bits. -+ unsigned XLen; -+ // Size of the floating point ('f') registers in bits. Note that the target -+ // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target -+ // with soft float ABI has FLen==0). -+ unsigned FLen; - static const int NumArgGPRs = 8; -+ static const int NumArgFPRs = 8; -+ bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, -+ llvm::Type *&Field1Ty, -+ CharUnits &Field1Off, -+ llvm::Type *&Field2Ty, -+ CharUnits &Field2Off) const; - - public: -- RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen) -- : DefaultABIInfo(CGT), XLen(XLen) {} -+ RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen) -+ : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {} - - // DefaultABIInfo's classifyReturnType and classifyArgumentType are - // non-virtual, but computeInfo is virtual, so we overload it. - void computeInfo(CGFunctionInfo &FI) const override; - -- ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, -- int &ArgGPRsLeft) const; -+ ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, -+ int &ArgFPRsLeft) const; - ABIArgInfo classifyReturnType(QualType RetTy) const; - - Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, - QualType Ty) const override; - - ABIArgInfo extendType(QualType Ty) const; -+ -+ bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, -+ CharUnits &Field1Off, llvm::Type *&Field2Ty, -+ CharUnits &Field2Off, int &NeededArgGPRs, -+ int &NeededArgFPRs) const; -+ ABIArgInfo coerceAndExpandFPCCEligibleStruct(llvm::Type *Field1Ty, -+ CharUnits Field1Off, -+ llvm::Type *Field2Ty, -+ CharUnits Field2Off) const; - }; - } // end anonymous namespace - -@@ -9228,18 +9248,215 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { - // different for variadic arguments, we must also track whether we are - // examining a vararg or not. - int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; -+ int ArgFPRsLeft = FLen ? NumArgFPRs : 0; - int NumFixedArgs = FI.getNumRequiredArgs(); - - int ArgNum = 0; - for (auto &ArgInfo : FI.arguments()) { - bool IsFixed = ArgNum < NumFixedArgs; -- ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft); -+ ArgInfo.info = -+ classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft); - ArgNum++; - } - } - -+// Returns true if the struct is a potential candidate for the floating point -+// calling convention. If this function returns true, the caller is -+// responsible for checking that if there is only a single field then that -+// field is a float. -+bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, -+ llvm::Type *&Field1Ty, -+ CharUnits &Field1Off, -+ llvm::Type *&Field2Ty, -+ CharUnits &Field2Off) const { -+ bool IsInt = Ty->isIntegralOrEnumerationType(); -+ bool IsFloat = Ty->isRealFloatingType(); -+ -+ if (IsInt || IsFloat) { -+ uint64_t Size = getContext().getTypeSize(Ty); -+ if (IsInt && Size > XLen) -+ return false; -+ // Can't be eligible if larger than the FP registers. Half precision isn't -+ // currently supported on RISC-V and the ABI hasn't been confirmed, so -+ // default to the integer ABI in that case. -+ if (IsFloat && (Size > FLen || Size < 32)) -+ return false; -+ // Can't be eligible if an integer type was already found (int+int pairs -+ // are not eligible). -+ if (IsInt && Field1Ty && Field1Ty->isIntegerTy()) -+ return false; -+ if (!Field1Ty) { -+ Field1Ty = CGT.ConvertType(Ty); -+ Field1Off = CurOff; -+ return true; -+ } -+ if (!Field2Ty) { -+ Field2Ty = CGT.ConvertType(Ty); -+ Field2Off = CurOff; -+ return true; -+ } -+ return false; -+ } -+ -+ if (auto CTy = Ty->getAs()) { -+ if (Field1Ty) -+ return false; -+ QualType EltTy = CTy->getElementType(); -+ if (getContext().getTypeSize(EltTy) > FLen) -+ return false; -+ Field1Ty = CGT.ConvertType(EltTy); -+ Field1Off = CurOff; -+ assert(CurOff.isZero() && "Unexpected offset for first field"); -+ Field2Ty = Field1Ty; -+ Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy); -+ return true; -+ } -+ -+ if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) { -+ uint64_t ArraySize = ATy->getSize().getZExtValue(); -+ QualType EltTy = ATy->getElementType(); -+ CharUnits EltSize = getContext().getTypeSizeInChars(EltTy); -+ for (uint64_t i = 0; i < ArraySize; ++i) { -+ bool Ret = detectFPCCEligibleStructHelper(EltTy, CurOff, Field1Ty, -+ Field1Off, Field2Ty, Field2Off); -+ if (!Ret) -+ return false; -+ CurOff += EltSize; -+ } -+ return true; -+ } -+ -+ if (const auto *RTy = Ty->getAs()) { -+ // Structures with either a non-trivial destructor or a non-trivial -+ // copy constructor are not eligible for the FP calling convention. -+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT.getCXXABI())) -+ return false; -+ if (isEmptyRecord(getContext(), Ty, true)) -+ return true; -+ const RecordDecl *RD = RTy->getDecl(); -+ // Unions aren't eligible unless they're empty (which is caught above). -+ if (RD->isUnion()) -+ return false; -+ int ZeroWidthBitFieldCount = 0; -+ for (const FieldDecl *FD : RD->fields()) { -+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); -+ uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex()); -+ QualType QTy = FD->getType(); -+ if (FD->isBitField()) { -+ unsigned BitWidth = FD->getBitWidthValue(getContext()); -+ // Allow a bitfield with a type greater than XLen as long as the -+ // bitwidth is XLen or less. -+ if (getContext().getTypeSize(QTy) > XLen && BitWidth <= XLen) -+ QTy = getContext().getIntTypeForBitwidth(XLen, false); -+ if (BitWidth == 0) { -+ ZeroWidthBitFieldCount++; -+ continue; -+ } -+ } -+ -+ bool Ret = detectFPCCEligibleStructHelper( -+ QTy, CurOff + getContext().toCharUnitsFromBits(FieldOffInBits), -+ Field1Ty, Field1Off, Field2Ty, Field2Off); -+ if (!Ret) -+ return false; -+ -+ // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp -+ // or int+fp structs, but are ignored for a struct with an fp field and -+ // any number of zero-width bitfields. -+ if (Field2Ty && ZeroWidthBitFieldCount > 0) -+ return false; -+ } -+ return Field1Ty != nullptr; -+ } -+ -+ return false; -+} -+ -+// Determine if a struct is eligible for passing according to the floating -+// point calling convention (i.e., when flattened it contains a single fp -+// value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and -+// NeededArgGPRs are incremented appropriately. -+bool RISCVABIInfo::detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, -+ CharUnits &Field1Off, -+ llvm::Type *&Field2Ty, -+ CharUnits &Field2Off, -+ int &NeededArgGPRs, -+ int &NeededArgFPRs) const { -+ Field1Ty = nullptr; -+ Field2Ty = nullptr; -+ NeededArgGPRs = 0; -+ NeededArgFPRs = 0; -+ bool IsCandidate = detectFPCCEligibleStructHelper( -+ Ty, CharUnits::Zero(), Field1Ty, Field1Off, Field2Ty, Field2Off); -+ // Not really a candidate if we have a single int but no float. -+ if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy()) -+ return IsCandidate = false; -+ if (!IsCandidate) -+ return false; -+ if (Field1Ty && Field1Ty->isFloatingPointTy()) -+ NeededArgFPRs++; -+ else if (Field1Ty) -+ NeededArgGPRs++; -+ if (Field2Ty && Field2Ty->isFloatingPointTy()) -+ NeededArgFPRs++; -+ else if (Field2Ty) -+ NeededArgGPRs++; -+ return IsCandidate; -+} -+ -+// Call getCoerceAndExpand for the two-element flattened struct described by -+// Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an -+// appropriate coerceToType and unpaddedCoerceToType. -+ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct( -+ llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty, -+ CharUnits Field2Off) const { -+ SmallVector CoerceElts; -+ SmallVector UnpaddedCoerceElts; -+ if (!Field1Off.isZero()) -+ CoerceElts.push_back(llvm::ArrayType::get( -+ llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity())); -+ -+ CoerceElts.push_back(Field1Ty); -+ UnpaddedCoerceElts.push_back(Field1Ty); -+ -+ if (!Field2Ty) { -+ return ABIArgInfo::getCoerceAndExpand( -+ llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()), -+ UnpaddedCoerceElts[0]); -+ } -+ -+ CharUnits Field2Align = -+ CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(Field2Ty)); -+ CharUnits Field1Size = -+ CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty)); -+ CharUnits Field2OffNoPadNoPack = Field1Size.alignTo(Field2Align); -+ -+ CharUnits Padding = CharUnits::Zero(); -+ if (Field2Off > Field2OffNoPadNoPack) -+ Padding = Field2Off - Field2OffNoPadNoPack; -+ else if (Field2Off != Field2Align && Field2Off > Field1Size) -+ Padding = Field2Off - Field1Size; -+ -+ bool IsPacked = !Field2Off.isMultipleOf(Field2Align); -+ -+ if (!Padding.isZero()) -+ CoerceElts.push_back(llvm::ArrayType::get( -+ llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity())); -+ -+ CoerceElts.push_back(Field2Ty); -+ UnpaddedCoerceElts.push_back(Field2Ty); -+ -+ auto CoerceToType = -+ llvm::StructType::get(getVMContext(), CoerceElts, IsPacked); -+ auto UnpaddedCoerceToType = -+ llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked); -+ -+ return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType); -+} -+ - ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, -- int &ArgGPRsLeft) const { -+ int &ArgGPRsLeft, -+ int &ArgFPRsLeft) const { - assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); - Ty = useFirstFieldIfTransparentUnion(Ty); - -@@ -9257,6 +9474,42 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, - return ABIArgInfo::getIgnore(); - - uint64_t Size = getContext().getTypeSize(Ty); -+ -+ // Pass floating point values via FPRs if possible. -+ if (IsFixed && Ty->isFloatingType() && FLen >= Size && ArgFPRsLeft) { -+ ArgFPRsLeft--; -+ return ABIArgInfo::getDirect(); -+ } -+ -+ // Complex types for the hard float ABI must be passed direct rather than -+ // using CoerceAndExpand. -+ if (IsFixed && Ty->isComplexType() && FLen && ArgFPRsLeft >= 2) { -+ QualType EltTy = Ty->getAs()->getElementType(); -+ if (getContext().getTypeSize(EltTy) <= FLen) { -+ ArgFPRsLeft -= 2; -+ return ABIArgInfo::getDirect(); -+ } -+ } -+ -+ if (IsFixed && FLen && Ty->isStructureOrClassType()) { -+ llvm::Type *Field1Ty = nullptr; -+ llvm::Type *Field2Ty = nullptr; -+ CharUnits Field1Off = CharUnits::Zero(); -+ CharUnits Field2Off = CharUnits::Zero(); -+ int NeededArgGPRs; -+ int NeededArgFPRs; -+ bool IsCandidate = -+ detectFPCCEligibleStruct(Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, -+ NeededArgGPRs, NeededArgFPRs); -+ if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft && -+ NeededArgFPRs <= ArgFPRsLeft) { -+ ArgGPRsLeft -= NeededArgGPRs; -+ ArgFPRsLeft -= NeededArgFPRs; -+ return coerceAndExpandFPCCEligibleStruct(Field1Ty, Field1Off, Field2Ty, -+ Field2Off); -+ } -+ } -+ - uint64_t NeededAlign = getContext().getTypeAlign(Ty); - bool MustUseStack = false; - // Determine the number of GPRs needed to pass the current argument -@@ -9315,10 +9568,12 @@ ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const { - return ABIArgInfo::getIgnore(); - - int ArgGPRsLeft = 2; -+ int ArgFPRsLeft = FLen ? 2 : 0; - - // The rules for return and argument types are the same, so defer to - // classifyArgumentType. -- return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft); -+ return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, -+ ArgFPRsLeft); - } - - Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, -@@ -9353,8 +9608,9 @@ ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const { - namespace { - class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { - public: -- RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen) -- : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen)) {} -+ RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, -+ unsigned FLen) -+ : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen, FLen)) {} - - void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const override { -@@ -9493,9 +9749,16 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { - return SetCGInfo(new MSP430TargetCodeGenInfo(Types)); - - case llvm::Triple::riscv32: -- return SetCGInfo(new RISCVTargetCodeGenInfo(Types, 32)); -- case llvm::Triple::riscv64: -- return SetCGInfo(new RISCVTargetCodeGenInfo(Types, 64)); -+ case llvm::Triple::riscv64: { -+ StringRef ABIStr = getTarget().getABI(); -+ unsigned XLen = getTarget().getPointerWidth(0); -+ unsigned ABIFLen = 0; -+ if (ABIStr.endswith("f")) -+ ABIFLen = 32; -+ else if (ABIStr.endswith("d")) -+ ABIFLen = 64; -+ return SetCGInfo(new RISCVTargetCodeGenInfo(Types, XLen, ABIFLen)); -+ } - - case llvm::Triple::systemz: { - bool HasVector = getTarget().getABI() == "vector"; -diff --git a/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c b/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c -index 0c2f0791e31..677040626f5 100644 ---- a/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c -+++ b/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c -@@ -1,4 +1,6 @@ - // RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s -+// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ -+// RUN: | FileCheck %s - - // This file contains test cases that will have the same output for the ilp32 - // and ilp32f ABIs. -@@ -35,8 +37,8 @@ int f_scalar_stack_1(int32_t a, int64_t b, int32_t c, double d, long double e, - // the presence of large return values that consume a register due to the need - // to pass a pointer. - --// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, i32 %a, i64 %b, i64 %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) --struct large f_scalar_stack_2(int32_t a, int64_t b, int64_t c, long double d, -+// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, i32 %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) -+struct large f_scalar_stack_2(int32_t a, int64_t b, double c, long double d, - uint8_t e, int8_t f, uint8_t g) { - return (struct large){a, e, f, g}; - } -diff --git a/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c -index 12837fce942..fa11c1772d7 100644 ---- a/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c -+++ b/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c -@@ -1,6 +1,10 @@ - // RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s - // RUN: %clang_cc1 -triple riscv32 -emit-llvm -fforce-enable-int128 %s -o - \ - // RUN: | FileCheck %s -check-prefixes=CHECK,CHECK-FORCEINT128 -+// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ -+// RUN: | FileCheck %s - - // This file contains test cases that will have the same output for the ilp32, - // ilp32f, and ilp32d ABIs. -diff --git a/clang/test/CodeGen/riscv32-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32d-abi.c -new file mode 100644 -index 00000000000..b10656cf123 ---- /dev/null -+++ b/clang/test/CodeGen/riscv32-ilp32d-abi.c -@@ -0,0 +1,282 @@ -+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+ -+#include -+ -+// Verify that the tracking of used GPRs and FPRs works correctly by checking -+// that small integers are sign/zero extended when passed in registers. -+ -+// Doubles are passed in FPRs, so argument 'i' will be passed zero-extended -+// because it will be passed in a GPR. -+ -+// CHECK: define void @f_fpr_tracking(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, i8 zeroext %i) -+void f_fpr_tracking(double a, double b, double c, double d, double e, double f, -+ double g, double h, uint8_t i) {} -+ -+// Check that fp, fp+fp, and int+fp structs are lowered correctly. These will -+// be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are -+// available the widths are <= XLEN and FLEN, and should be expanded to -+// separate arguments in IR. They are passed by the same rules for returns, -+// but will be lowered to simple two-element structs if necessary (as LLVM IR -+// functions cannot return multiple values). -+ -+// A struct containing just one floating-point real is passed as though it -+// were a standalone floating-point real. -+ -+struct double_s { double f; }; -+ -+// CHECK: define void @f_double_s_arg(double) -+void f_double_s_arg(struct double_s a) {} -+ -+// CHECK: define double @f_ret_double_s() -+struct double_s f_ret_double_s() { -+ return (struct double_s){1.0}; -+} -+ -+// A struct containing a double and any number of zero-width bitfields is -+// passed as though it were a standalone floating-point real. -+ -+struct zbf_double_s { int : 0; double f; }; -+struct zbf_double_zbf_s { int : 0; double f; int : 0; }; -+ -+// CHECK: define void @f_zbf_double_s_arg(double) -+void f_zbf_double_s_arg(struct zbf_double_s a) {} -+ -+// CHECK: define double @f_ret_zbf_double_s() -+struct zbf_double_s f_ret_zbf_double_s() { -+ return (struct zbf_double_s){1.0}; -+} -+ -+// CHECK: define void @f_zbf_double_zbf_s_arg(double) -+void f_zbf_double_zbf_s_arg(struct zbf_double_zbf_s a) {} -+ -+// CHECK: define double @f_ret_zbf_double_zbf_s() -+struct zbf_double_zbf_s f_ret_zbf_double_zbf_s() { -+ return (struct zbf_double_zbf_s){1.0}; -+} -+ -+// Check that structs containing two floating point values (FLEN <= width) are -+// expanded provided sufficient FPRs are available. -+ -+struct double_double_s { double f; double g; }; -+struct double_float_s { double f; float g; }; -+ -+// CHECK: define void @f_double_double_s_arg(double, double) -+void f_double_double_s_arg(struct double_double_s a) {} -+ -+// CHECK: define { double, double } @f_ret_double_double_s() -+struct double_double_s f_ret_double_double_s() { -+ return (struct double_double_s){1.0, 2.0}; -+} -+ -+// CHECK: define void @f_double_float_s_arg(double, float) -+void f_double_float_s_arg(struct double_float_s a) {} -+ -+// CHECK: define { double, float } @f_ret_double_float_s() -+struct double_float_s f_ret_double_float_s() { -+ return (struct double_float_s){1.0, 2.0}; -+} -+ -+// CHECK: define void @f_double_double_s_arg_insufficient_fprs(float %a, double %b, double %c, double %d, double %e, double %f, double %g, %struct.double_double_s* %h) -+void f_double_double_s_arg_insufficient_fprs(float a, double b, double c, double d, -+ double e, double f, double g, struct double_double_s h) {} -+ -+// Check that structs containing int+double values are expanded, provided -+// sufficient FPRs and GPRs are available. The integer components are neither -+// sign or zero-extended. -+ -+struct double_int8_s { double f; int8_t i; }; -+struct double_uint8_s { double f; uint8_t i; }; -+struct double_int32_s { double f; int32_t i; }; -+struct double_int64_s { double f; int64_t i; }; -+struct double_int64bf_s { double f; int64_t i : 32; }; -+struct double_int8_zbf_s { double f; int8_t i; int : 0; }; -+ -+// CHECK: define void @f_double_int8_s_arg(double, i8) -+void f_double_int8_s_arg(struct double_int8_s a) {} -+ -+// CHECK: define { double, i8 } @f_ret_double_int8_s() -+struct double_int8_s f_ret_double_int8_s() { -+ return (struct double_int8_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_uint8_s_arg(double, i8) -+void f_double_uint8_s_arg(struct double_uint8_s a) {} -+ -+// CHECK: define { double, i8 } @f_ret_double_uint8_s() -+struct double_uint8_s f_ret_double_uint8_s() { -+ return (struct double_uint8_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_int32_s_arg(double, i32) -+void f_double_int32_s_arg(struct double_int32_s a) {} -+ -+// CHECK: define { double, i32 } @f_ret_double_int32_s() -+struct double_int32_s f_ret_double_int32_s() { -+ return (struct double_int32_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_int64_s_arg(%struct.double_int64_s* %a) -+void f_double_int64_s_arg(struct double_int64_s a) {} -+ -+// CHECK: define void @f_ret_double_int64_s(%struct.double_int64_s* noalias sret %agg.result) -+struct double_int64_s f_ret_double_int64_s() { -+ return (struct double_int64_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_int64bf_s_arg(double, i32) -+void f_double_int64bf_s_arg(struct double_int64bf_s a) {} -+ -+// CHECK: define { double, i32 } @f_ret_double_int64bf_s() -+struct double_int64bf_s f_ret_double_int64bf_s() { -+ return (struct double_int64bf_s){1.0, 2}; -+} -+ -+// The zero-width bitfield means the struct can't be passed according to the -+// floating point calling convention. -+ -+// CHECK: define void @f_double_int8_zbf_s(double, i8) -+void f_double_int8_zbf_s(struct double_int8_zbf_s a) {} -+ -+// CHECK: define { double, i8 } @f_ret_double_int8_zbf_s() -+struct double_int8_zbf_s f_ret_double_int8_zbf_s() { -+ return (struct double_int8_zbf_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, %struct.double_int8_s* %i) -+void f_double_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e, -+ int f, int g, int h, struct double_int8_s i) {} -+ -+// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, %struct.double_int8_s* %i) -+void f_struct_double_int8_insufficient_fprs(float a, double b, double c, double d, -+ double e, double f, double g, double h, struct double_int8_s i) {} -+ -+// Complex floating-point values or structs containing a single complex -+// floating-point value should be passed as if it were an fp+fp struct. -+ -+// CHECK: define void @f_doublecomplex(double %a.coerce0, double %a.coerce1) -+void f_doublecomplex(double __complex__ a) {} -+ -+// CHECK: define { double, double } @f_ret_doublecomplex() -+double __complex__ f_ret_doublecomplex() { -+ return 1.0; -+} -+ -+struct doublecomplex_s { double __complex__ c; }; -+ -+// CHECK: define void @f_doublecomplex_s_arg(double, double) -+void f_doublecomplex_s_arg(struct doublecomplex_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublecomplex_s() -+struct doublecomplex_s f_ret_doublecomplex_s() { -+ return (struct doublecomplex_s){1.0}; -+} -+ -+// Test single or two-element structs that need flattening. e.g. those -+// containing nested structs, doubles in small arrays, zero-length structs etc. -+ -+struct doublearr1_s { double a[1]; }; -+ -+// CHECK: define void @f_doublearr1_s_arg(double) -+void f_doublearr1_s_arg(struct doublearr1_s a) {} -+ -+// CHECK: define double @f_ret_doublearr1_s() -+struct doublearr1_s f_ret_doublearr1_s() { -+ return (struct doublearr1_s){{1.0}}; -+} -+ -+struct doublearr2_s { double a[2]; }; -+ -+// CHECK: define void @f_doublearr2_s_arg(double, double) -+void f_doublearr2_s_arg(struct doublearr2_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_s() -+struct doublearr2_s f_ret_doublearr2_s() { -+ return (struct doublearr2_s){{1.0, 2.0}}; -+} -+ -+struct doublearr2_tricky1_s { struct { double f[1]; } g[2]; }; -+ -+// CHECK: define void @f_doublearr2_tricky1_s_arg(double, double) -+void f_doublearr2_tricky1_s_arg(struct doublearr2_tricky1_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() -+struct doublearr2_tricky1_s f_ret_doublearr2_tricky1_s() { -+ return (struct doublearr2_tricky1_s){{{{1.0}}, {{2.0}}}}; -+} -+ -+struct doublearr2_tricky2_s { struct {}; struct { double f[1]; } g[2]; }; -+ -+// CHECK: define void @f_doublearr2_tricky2_s_arg(double, double) -+void f_doublearr2_tricky2_s_arg(struct doublearr2_tricky2_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() -+struct doublearr2_tricky2_s f_ret_doublearr2_tricky2_s() { -+ return (struct doublearr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}}; -+} -+ -+struct doublearr2_tricky3_s { union {}; struct { double f[1]; } g[2]; }; -+ -+// CHECK: define void @f_doublearr2_tricky3_s_arg(double, double) -+void f_doublearr2_tricky3_s_arg(struct doublearr2_tricky3_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_tricky3_s() -+struct doublearr2_tricky3_s f_ret_doublearr2_tricky3_s() { -+ return (struct doublearr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}}; -+} -+ -+struct doublearr2_tricky4_s { union {}; struct { struct {}; double f[1]; } g[2]; }; -+ -+// CHECK: define void @f_doublearr2_tricky4_s_arg(double, double) -+void f_doublearr2_tricky4_s_arg(struct doublearr2_tricky4_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_tricky4_s() -+struct doublearr2_tricky4_s f_ret_doublearr2_tricky4_s() { -+ return (struct doublearr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}}; -+} -+ -+// Test structs that should be passed according to the normal integer calling -+// convention. -+ -+struct int_double_int_s { int a; double b; int c; }; -+ -+// CHECK: define void @f_int_double_int_s_arg(%struct.int_double_int_s* %a) -+void f_int_double_int_s_arg(struct int_double_int_s a) {} -+ -+// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret %agg.result) -+struct int_double_int_s f_ret_int_double_int_s() { -+ return (struct int_double_int_s){1, 2.0, 3}; -+} -+ -+struct int64_double_s { int64_t a; double b; }; -+ -+// CHECK: define void @f_int64_double_s_arg(%struct.int64_double_s* %a) -+void f_int64_double_s_arg(struct int64_double_s a) {} -+ -+// CHECK: define void @f_ret_int64_double_s(%struct.int64_double_s* noalias sret %agg.result) -+struct int64_double_s f_ret_int64_double_s() { -+ return (struct int64_double_s){1, 2.0}; -+} -+ -+struct char_char_double_s { char a; char b; double c; }; -+ -+// CHECK-LABEL: define void @f_char_char_double_s_arg(%struct.char_char_double_s* %a) -+void f_char_char_double_s_arg(struct char_char_double_s a) {} -+ -+// CHECK: define void @f_ret_char_char_double_s(%struct.char_char_double_s* noalias sret %agg.result) -+struct char_char_double_s f_ret_char_char_double_s() { -+ return (struct char_char_double_s){1, 2, 3.0}; -+} -+ -+// Unions are always passed according to the integer calling convention, even -+// if they can only contain a double. -+ -+union double_u { double a; }; -+ -+// CHECK: define void @f_double_u_arg(i64 %a.coerce) -+void f_double_u_arg(union double_u a) {} -+ -+// CHECK: define i64 @f_ret_double_u() -+union double_u f_ret_double_u() { -+ return (union double_u){1.0}; -+} -diff --git a/clang/test/CodeGen/riscv32-ilp32f-abi.c b/clang/test/CodeGen/riscv32-ilp32f-abi.c -new file mode 100644 -index 00000000000..76092958aed ---- /dev/null -+++ b/clang/test/CodeGen/riscv32-ilp32f-abi.c -@@ -0,0 +1,45 @@ -+// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+ -+#include -+ -+// Doubles are still passed in GPRs, so the 'e' argument will be anyext as -+// GPRs are exhausted. -+ -+// CHECK: define void @f_fpr_tracking(double %a, double %b, double %c, double %d, i8 %e) -+void f_fpr_tracking(double a, double b, double c, double d, int8_t e) {} -+ -+// Lowering for doubles is unnmodified, as 64 > FLEN. -+ -+struct double_s { double d; }; -+ -+// CHECK: define void @f_double_s_arg(i64 %a.coerce) -+void f_double_s_arg(struct double_s a) {} -+ -+// CHECK: define i64 @f_ret_double_s() -+struct double_s f_ret_double_s() { -+ return (struct double_s){1.0}; -+} -+ -+struct double_double_s { double d; double e; }; -+ -+// CHECK: define void @f_double_double_s_arg(%struct.double_double_s* %a) -+void f_double_double_s_arg(struct double_double_s a) {} -+ -+// CHECK: define void @f_ret_double_double_s(%struct.double_double_s* noalias sret %agg.result) -+struct double_double_s f_ret_double_double_s() { -+ return (struct double_double_s){1.0, 2.0}; -+} -+ -+struct double_int8_s { double d; int64_t i; }; -+ -+struct int_double_s { int a; double b; }; -+ -+// CHECK: define void @f_int_double_s_arg(%struct.int_double_s* %a) -+void f_int_double_s_arg(struct int_double_s a) {} -+ -+// CHECK: define void @f_ret_int_double_s(%struct.int_double_s* noalias sret %agg.result) -+struct int_double_s f_ret_int_double_s() { -+ return (struct int_double_s){1, 2.0}; -+} -+ -diff --git a/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c -new file mode 100644 -index 00000000000..b960513655b ---- /dev/null -+++ b/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c -@@ -0,0 +1,275 @@ -+// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+ -+#include -+ -+// Verify that the tracking of used GPRs and FPRs works correctly by checking -+// that small integers are sign/zero extended when passed in registers. -+ -+// Floats are passed in FPRs, so argument 'i' will be passed zero-extended -+// because it will be passed in a GPR. -+ -+// CHECK: define void @f_fpr_tracking(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, i8 zeroext %i) -+void f_fpr_tracking(float a, float b, float c, float d, float e, float f, -+ float g, float h, uint8_t i) {} -+ -+// Check that fp, fp+fp, and int+fp structs are lowered correctly. These will -+// be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are -+// available the widths are <= XLEN and FLEN, and should be expanded to -+// separate arguments in IR. They are passed by the same rules for returns, -+// but will be lowered to simple two-element structs if necessary (as LLVM IR -+// functions cannot return multiple values). -+ -+// A struct containing just one floating-point real is passed as though it -+// were a standalone floating-point real. -+ -+struct float_s { float f; }; -+ -+// CHECK: define void @f_float_s_arg(float) -+void f_float_s_arg(struct float_s a) {} -+ -+// CHECK: define float @f_ret_float_s() -+struct float_s f_ret_float_s() { -+ return (struct float_s){1.0}; -+} -+ -+// A struct containing a float and any number of zero-width bitfields is -+// passed as though it were a standalone floating-point real. -+ -+struct zbf_float_s { int : 0; float f; }; -+struct zbf_float_zbf_s { int : 0; float f; int : 0; }; -+ -+// CHECK: define void @f_zbf_float_s_arg(float) -+void f_zbf_float_s_arg(struct zbf_float_s a) {} -+ -+// CHECK: define float @f_ret_zbf_float_s() -+struct zbf_float_s f_ret_zbf_float_s() { -+ return (struct zbf_float_s){1.0}; -+} -+ -+// CHECK: define void @f_zbf_float_zbf_s_arg(float) -+void f_zbf_float_zbf_s_arg(struct zbf_float_zbf_s a) {} -+ -+// CHECK: define float @f_ret_zbf_float_zbf_s() -+struct zbf_float_zbf_s f_ret_zbf_float_zbf_s() { -+ return (struct zbf_float_zbf_s){1.0}; -+} -+ -+// Check that structs containing two float values (FLEN <= width) are expanded -+// provided sufficient FPRs are available. -+ -+struct float_float_s { float f; float g; }; -+ -+// CHECK: define void @f_float_float_s_arg(float, float) -+void f_float_float_s_arg(struct float_float_s a) {} -+ -+// CHECK: define { float, float } @f_ret_float_float_s() -+struct float_float_s f_ret_float_float_s() { -+ return (struct float_float_s){1.0, 2.0}; -+} -+ -+// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, [2 x i32] %h.coerce) -+void f_float_float_s_arg_insufficient_fprs(float a, float b, float c, float d, -+ float e, float f, float g, struct float_float_s h) {} -+ -+// Check that structs containing int+float values are expanded, provided -+// sufficient FPRs and GPRs are available. The integer components are neither -+// sign or zero-extended. -+ -+struct float_int8_s { float f; int8_t i; }; -+struct float_uint8_s { float f; uint8_t i; }; -+struct float_int32_s { float f; int32_t i; }; -+struct float_int64_s { float f; int64_t i; }; -+struct float_int64bf_s { float f; int64_t i : 32; }; -+struct float_int8_zbf_s { float f; int8_t i; int : 0; }; -+ -+// CHECK: define void @f_float_int8_s_arg(float, i8) -+void f_float_int8_s_arg(struct float_int8_s a) {} -+ -+// CHECK: define { float, i8 } @f_ret_float_int8_s() -+struct float_int8_s f_ret_float_int8_s() { -+ return (struct float_int8_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_uint8_s_arg(float, i8) -+void f_float_uint8_s_arg(struct float_uint8_s a) {} -+ -+// CHECK: define { float, i8 } @f_ret_float_uint8_s() -+struct float_uint8_s f_ret_float_uint8_s() { -+ return (struct float_uint8_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_int32_s_arg(float, i32) -+void f_float_int32_s_arg(struct float_int32_s a) {} -+ -+// CHECK: define { float, i32 } @f_ret_float_int32_s() -+struct float_int32_s f_ret_float_int32_s() { -+ return (struct float_int32_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_int64_s_arg(%struct.float_int64_s* %a) -+void f_float_int64_s_arg(struct float_int64_s a) {} -+ -+// CHECK: define void @f_ret_float_int64_s(%struct.float_int64_s* noalias sret %agg.result) -+struct float_int64_s f_ret_float_int64_s() { -+ return (struct float_int64_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_int64bf_s_arg(float, i32) -+void f_float_int64bf_s_arg(struct float_int64bf_s a) {} -+ -+// CHECK: define { float, i32 } @f_ret_float_int64bf_s() -+struct float_int64bf_s f_ret_float_int64bf_s() { -+ return (struct float_int64bf_s){1.0, 2}; -+} -+ -+// The zero-width bitfield means the struct can't be passed according to the -+// floating point calling convention. -+ -+// CHECK: define void @f_float_int8_zbf_s(float, i8) -+void f_float_int8_zbf_s(struct float_int8_zbf_s a) {} -+ -+// CHECK: define { float, i8 } @f_ret_float_int8_zbf_s() -+struct float_int8_zbf_s f_ret_float_int8_zbf_s() { -+ return (struct float_int8_zbf_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, [2 x i32] %i.coerce) -+void f_float_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e, -+ int f, int g, int h, struct float_int8_s i) {} -+ -+// CHECK: define void @f_struct_float_int8_insufficient_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, [2 x i32] %i.coerce) -+void f_struct_float_int8_insufficient_fprs(float a, float b, float c, float d, -+ float e, float f, float g, float h, struct float_int8_s i) {} -+ -+// Complex floating-point values or structs containing a single complex -+// floating-point value should be passed as if it were an fp+fp struct. -+ -+// CHECK: define void @f_floatcomplex(float %a.coerce0, float %a.coerce1) -+void f_floatcomplex(float __complex__ a) {} -+ -+// CHECK: define { float, float } @f_ret_floatcomplex() -+float __complex__ f_ret_floatcomplex() { -+ return 1.0; -+} -+ -+struct floatcomplex_s { float __complex__ c; }; -+ -+// CHECK: define void @f_floatcomplex_s_arg(float, float) -+void f_floatcomplex_s_arg(struct floatcomplex_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatcomplex_s() -+struct floatcomplex_s f_ret_floatcomplex_s() { -+ return (struct floatcomplex_s){1.0}; -+} -+ -+// Test single or two-element structs that need flattening. e.g. those -+// containing nested structs, floats in small arrays, zero-length structs etc. -+ -+struct floatarr1_s { float a[1]; }; -+ -+// CHECK: define void @f_floatarr1_s_arg(float) -+void f_floatarr1_s_arg(struct floatarr1_s a) {} -+ -+// CHECK: define float @f_ret_floatarr1_s() -+struct floatarr1_s f_ret_floatarr1_s() { -+ return (struct floatarr1_s){{1.0}}; -+} -+ -+struct floatarr2_s { float a[2]; }; -+ -+// CHECK: define void @f_floatarr2_s_arg(float, float) -+void f_floatarr2_s_arg(struct floatarr2_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_s() -+struct floatarr2_s f_ret_floatarr2_s() { -+ return (struct floatarr2_s){{1.0, 2.0}}; -+} -+ -+struct floatarr2_tricky1_s { struct { float f[1]; } g[2]; }; -+ -+// CHECK: define void @f_floatarr2_tricky1_s_arg(float, float) -+void f_floatarr2_tricky1_s_arg(struct floatarr2_tricky1_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s() -+struct floatarr2_tricky1_s f_ret_floatarr2_tricky1_s() { -+ return (struct floatarr2_tricky1_s){{{{1.0}}, {{2.0}}}}; -+} -+ -+struct floatarr2_tricky2_s { struct {}; struct { float f[1]; } g[2]; }; -+ -+// CHECK: define void @f_floatarr2_tricky2_s_arg(float, float) -+void f_floatarr2_tricky2_s_arg(struct floatarr2_tricky2_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s() -+struct floatarr2_tricky2_s f_ret_floatarr2_tricky2_s() { -+ return (struct floatarr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}}; -+} -+ -+struct floatarr2_tricky3_s { union {}; struct { float f[1]; } g[2]; }; -+ -+// CHECK: define void @f_floatarr2_tricky3_s_arg(float, float) -+void f_floatarr2_tricky3_s_arg(struct floatarr2_tricky3_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_tricky3_s() -+struct floatarr2_tricky3_s f_ret_floatarr2_tricky3_s() { -+ return (struct floatarr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}}; -+} -+ -+struct floatarr2_tricky4_s { union {}; struct { struct {}; float f[1]; } g[2]; }; -+ -+// CHECK: define void @f_floatarr2_tricky4_s_arg(float, float) -+void f_floatarr2_tricky4_s_arg(struct floatarr2_tricky4_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_tricky4_s() -+struct floatarr2_tricky4_s f_ret_floatarr2_tricky4_s() { -+ return (struct floatarr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}}; -+} -+ -+// Test structs that should be passed according to the normal integer calling -+// convention. -+ -+struct int_float_int_s { int a; float b; int c; }; -+ -+// CHECK: define void @f_int_float_int_s_arg(%struct.int_float_int_s* %a) -+void f_int_float_int_s_arg(struct int_float_int_s a) {} -+ -+// CHECK: define void @f_ret_int_float_int_s(%struct.int_float_int_s* noalias sret %agg.result) -+struct int_float_int_s f_ret_int_float_int_s() { -+ return (struct int_float_int_s){1, 2.0, 3}; -+} -+ -+struct int64_float_s { int64_t a; float b; }; -+ -+// CHECK: define void @f_int64_float_s_arg(%struct.int64_float_s* %a) -+void f_int64_float_s_arg(struct int64_float_s a) {} -+ -+// CHECK: define void @f_ret_int64_float_s(%struct.int64_float_s* noalias sret %agg.result) -+struct int64_float_s f_ret_int64_float_s() { -+ return (struct int64_float_s){1, 2.0}; -+} -+ -+struct char_char_float_s { char a; char b; float c; }; -+ -+// CHECK-LABEL: define void @f_char_char_float_s_arg([2 x i32] %a.coerce) -+void f_char_char_float_s_arg(struct char_char_float_s a) {} -+ -+// CHECK: define [2 x i32] @f_ret_char_char_float_s() -+struct char_char_float_s f_ret_char_char_float_s() { -+ return (struct char_char_float_s){1, 2, 3.0}; -+} -+ -+// Unions are always passed according to the integer calling convention, even -+// if they can only contain a float. -+ -+union float_u { float a; }; -+ -+// CHECK: define void @f_float_u_arg(i32 %a.coerce) -+void f_float_u_arg(union float_u a) {} -+ -+// CHECK: define i32 @f_ret_float_u() -+union float_u f_ret_float_u() { -+ return (union float_u){1.0}; -+} -diff --git a/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c b/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c -index 3b944e716a2..d457bdf3c64 100644 ---- a/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c -+++ b/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c -@@ -1,4 +1,6 @@ - // RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - | FileCheck %s -+// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \ -+// RUN: | FileCheck %s - - // This file contains test cases that will have the same output for the lp64 - // and lp64f ABIs. -diff --git a/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c -index f51d8252b8f..f3523702e9a 100644 ---- a/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c -+++ b/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c -@@ -1,4 +1,8 @@ - // RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - | FileCheck %s -+// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ -+// RUN: | FileCheck %s - - // This file contains test cases that will have the same output for the lp64, - // lp64f, and lp64d ABIs. -diff --git a/clang/test/CodeGen/riscv64-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64d-abi.c -new file mode 100644 -index 00000000000..00967b5fca8 ---- /dev/null -+++ b/clang/test/CodeGen/riscv64-lp64d-abi.c -@@ -0,0 +1,272 @@ -+// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+ -+#include -+ -+// Verify that the tracking of used GPRs and FPRs works correctly by checking -+// that small integers are sign/zero extended when passed in registers. -+ -+// Doubles are passed in FPRs, so argument 'i' will be passed zero-extended -+// because it will be passed in a GPR. -+ -+// CHECK: define void @f_fpr_tracking(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, i8 zeroext %i) -+void f_fpr_tracking(double a, double b, double c, double d, double e, double f, -+ double g, double h, uint8_t i) {} -+ -+// Check that fp, fp+fp, and int+fp structs are lowered correctly. These will -+// be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are -+// available the widths are <= XLEN and FLEN, and should be expanded to -+// separate arguments in IR. They are passed by the same rules for returns, -+// but will be lowered to simple two-element structs if necessary (as LLVM IR -+// functions cannot return multiple values). -+ -+// A struct containing just one floating-point real is passed as though it -+// were a standalone floating-point real. -+ -+struct double_s { double f; }; -+ -+// CHECK: define void @f_double_s_arg(double) -+void f_double_s_arg(struct double_s a) {} -+ -+// CHECK: define double @f_ret_double_s() -+struct double_s f_ret_double_s() { -+ return (struct double_s){1.0}; -+} -+ -+// A struct containing a double and any number of zero-width bitfields is -+// passed as though it were a standalone floating-point real. -+ -+struct zbf_double_s { int : 0; double f; }; -+struct zbf_double_zbf_s { int : 0; double f; int : 0; }; -+ -+// CHECK: define void @f_zbf_double_s_arg(double) -+void f_zbf_double_s_arg(struct zbf_double_s a) {} -+ -+// CHECK: define double @f_ret_zbf_double_s() -+struct zbf_double_s f_ret_zbf_double_s() { -+ return (struct zbf_double_s){1.0}; -+} -+ -+// CHECK: define void @f_zbf_double_zbf_s_arg(double) -+void f_zbf_double_zbf_s_arg(struct zbf_double_zbf_s a) {} -+ -+// CHECK: define double @f_ret_zbf_double_zbf_s() -+struct zbf_double_zbf_s f_ret_zbf_double_zbf_s() { -+ return (struct zbf_double_zbf_s){1.0}; -+} -+ -+// Check that structs containing two floating point values (FLEN <= width) are -+// expanded provided sufficient FPRs are available. -+ -+struct double_double_s { double f; double g; }; -+struct double_float_s { double f; float g; }; -+ -+// CHECK: define void @f_double_double_s_arg(double, double) -+void f_double_double_s_arg(struct double_double_s a) {} -+ -+// CHECK: define { double, double } @f_ret_double_double_s() -+struct double_double_s f_ret_double_double_s() { -+ return (struct double_double_s){1.0, 2.0}; -+} -+ -+// CHECK: define void @f_double_float_s_arg(double, float) -+void f_double_float_s_arg(struct double_float_s a) {} -+ -+// CHECK: define { double, float } @f_ret_double_float_s() -+struct double_float_s f_ret_double_float_s() { -+ return (struct double_float_s){1.0, 2.0}; -+} -+ -+// CHECK: define void @f_double_double_s_arg_insufficient_fprs(float %a, double %b, double %c, double %d, double %e, double %f, double %g, [2 x i64] %h.coerce) -+void f_double_double_s_arg_insufficient_fprs(float a, double b, double c, double d, -+ double e, double f, double g, struct double_double_s h) {} -+ -+// Check that structs containing int+double values are expanded, provided -+// sufficient FPRs and GPRs are available. The integer components are neither -+// sign or zero-extended. -+ -+struct double_int8_s { double f; int8_t i; }; -+struct double_uint8_s { double f; uint8_t i; }; -+struct double_int32_s { double f; int32_t i; }; -+struct double_int64_s { double f; int64_t i; }; -+struct double_int128bf_s { double f; __int128_t i : 64; }; -+struct double_int8_zbf_s { double f; int8_t i; int : 0; }; -+ -+// CHECK: define void @f_double_int8_s_arg(double, i8) -+void f_double_int8_s_arg(struct double_int8_s a) {} -+ -+// CHECK: define { double, i8 } @f_ret_double_int8_s() -+struct double_int8_s f_ret_double_int8_s() { -+ return (struct double_int8_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_uint8_s_arg(double, i8) -+void f_double_uint8_s_arg(struct double_uint8_s a) {} -+ -+// CHECK: define { double, i8 } @f_ret_double_uint8_s() -+struct double_uint8_s f_ret_double_uint8_s() { -+ return (struct double_uint8_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_int32_s_arg(double, i32) -+void f_double_int32_s_arg(struct double_int32_s a) {} -+ -+// CHECK: define { double, i32 } @f_ret_double_int32_s() -+struct double_int32_s f_ret_double_int32_s() { -+ return (struct double_int32_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_int64_s_arg(double, i64) -+void f_double_int64_s_arg(struct double_int64_s a) {} -+ -+// CHECK: define { double, i64 } @f_ret_double_int64_s() -+struct double_int64_s f_ret_double_int64_s() { -+ return (struct double_int64_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_int128bf_s_arg(double, i64) -+void f_double_int128bf_s_arg(struct double_int128bf_s a) {} -+ -+// CHECK: define { double, i64 } @f_ret_double_int128bf_s() -+struct double_int128bf_s f_ret_double_int128bf_s() { -+ return (struct double_int128bf_s){1.0, 2}; -+} -+ -+// The zero-width bitfield means the struct can't be passed according to the -+// floating point calling convention. -+ -+// CHECK: define void @f_double_int8_zbf_s(double, i8) -+void f_double_int8_zbf_s(struct double_int8_zbf_s a) {} -+ -+// CHECK: define { double, i8 } @f_ret_double_int8_zbf_s() -+struct double_int8_zbf_s f_ret_double_int8_zbf_s() { -+ return (struct double_int8_zbf_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, [2 x i64] %i.coerce) -+void f_double_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e, -+ int f, int g, int h, struct double_int8_s i) {} -+ -+// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, [2 x i64] %i.coerce) -+void f_struct_double_int8_insufficient_fprs(float a, double b, double c, double d, -+ double e, double f, double g, double h, struct double_int8_s i) {} -+ -+// Complex floating-point values or structs containing a single complex -+// floating-point value should be passed as if it were an fp+fp struct. -+ -+// CHECK: define void @f_doublecomplex(double %a.coerce0, double %a.coerce1) -+void f_doublecomplex(double __complex__ a) {} -+ -+// CHECK: define { double, double } @f_ret_doublecomplex() -+double __complex__ f_ret_doublecomplex() { -+ return 1.0; -+} -+ -+struct doublecomplex_s { double __complex__ c; }; -+ -+// CHECK: define void @f_doublecomplex_s_arg(double, double) -+void f_doublecomplex_s_arg(struct doublecomplex_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublecomplex_s() -+struct doublecomplex_s f_ret_doublecomplex_s() { -+ return (struct doublecomplex_s){1.0}; -+} -+ -+// Test single or two-element structs that need flattening. e.g. those -+// containing nested structs, doubles in small arrays, zero-length structs etc. -+ -+struct doublearr1_s { double a[1]; }; -+ -+// CHECK: define void @f_doublearr1_s_arg(double) -+void f_doublearr1_s_arg(struct doublearr1_s a) {} -+ -+// CHECK: define double @f_ret_doublearr1_s() -+struct doublearr1_s f_ret_doublearr1_s() { -+ return (struct doublearr1_s){{1.0}}; -+} -+ -+struct doublearr2_s { double a[2]; }; -+ -+// CHECK: define void @f_doublearr2_s_arg(double, double) -+void f_doublearr2_s_arg(struct doublearr2_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_s() -+struct doublearr2_s f_ret_doublearr2_s() { -+ return (struct doublearr2_s){{1.0, 2.0}}; -+} -+ -+struct doublearr2_tricky1_s { struct { double f[1]; } g[2]; }; -+ -+// CHECK: define void @f_doublearr2_tricky1_s_arg(double, double) -+void f_doublearr2_tricky1_s_arg(struct doublearr2_tricky1_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() -+struct doublearr2_tricky1_s f_ret_doublearr2_tricky1_s() { -+ return (struct doublearr2_tricky1_s){{{{1.0}}, {{2.0}}}}; -+} -+ -+struct doublearr2_tricky2_s { struct {}; struct { double f[1]; } g[2]; }; -+ -+// CHECK: define void @f_doublearr2_tricky2_s_arg(double, double) -+void f_doublearr2_tricky2_s_arg(struct doublearr2_tricky2_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() -+struct doublearr2_tricky2_s f_ret_doublearr2_tricky2_s() { -+ return (struct doublearr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}}; -+} -+ -+struct doublearr2_tricky3_s { union {}; struct { double f[1]; } g[2]; }; -+ -+// CHECK: define void @f_doublearr2_tricky3_s_arg(double, double) -+void f_doublearr2_tricky3_s_arg(struct doublearr2_tricky3_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_tricky3_s() -+struct doublearr2_tricky3_s f_ret_doublearr2_tricky3_s() { -+ return (struct doublearr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}}; -+} -+ -+struct doublearr2_tricky4_s { union {}; struct { struct {}; double f[1]; } g[2]; }; -+ -+// CHECK: define void @f_doublearr2_tricky4_s_arg(double, double) -+void f_doublearr2_tricky4_s_arg(struct doublearr2_tricky4_s a) {} -+ -+// CHECK: define { double, double } @f_ret_doublearr2_tricky4_s() -+struct doublearr2_tricky4_s f_ret_doublearr2_tricky4_s() { -+ return (struct doublearr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}}; -+} -+ -+// Test structs that should be passed according to the normal integer calling -+// convention. -+ -+struct int_double_int_s { int a; double b; int c; }; -+ -+// CHECK: define void @f_int_double_int_s_arg(%struct.int_double_int_s* %a) -+void f_int_double_int_s_arg(struct int_double_int_s a) {} -+ -+// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret %agg.result) -+struct int_double_int_s f_ret_int_double_int_s() { -+ return (struct int_double_int_s){1, 2.0, 3}; -+} -+ -+struct char_char_double_s { char a; char b; double c; }; -+ -+// CHECK-LABEL: define void @f_char_char_double_s_arg([2 x i64] %a.coerce) -+void f_char_char_double_s_arg(struct char_char_double_s a) {} -+ -+// CHECK: define [2 x i64] @f_ret_char_char_double_s() -+struct char_char_double_s f_ret_char_char_double_s() { -+ return (struct char_char_double_s){1, 2, 3.0}; -+} -+ -+// Unions are always passed according to the integer calling convention, even -+// if they can only contain a double. -+ -+union double_u { double a; }; -+ -+// CHECK: define void @f_double_u_arg(i64 %a.coerce) -+void f_double_u_arg(union double_u a) {} -+ -+// CHECK: define i64 @f_ret_double_u() -+union double_u f_ret_double_u() { -+ return (union double_u){1.0}; -+} -diff --git a/clang/test/CodeGen/riscv64-lp64f-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64f-lp64d-abi.c -new file mode 100644 -index 00000000000..eee2bc1bdcc ---- /dev/null -+++ b/clang/test/CodeGen/riscv64-lp64f-lp64d-abi.c -@@ -0,0 +1,265 @@ -+// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ -+// RUN: | FileCheck %s -+ -+#include -+ -+// Verify that the tracking of used GPRs and FPRs works correctly by checking -+// that small integers are sign/zero extended when passed in registers. -+ -+// Floats are passed in FPRs, so argument 'i' will be passed zero-extended -+// because it will be passed in a GPR. -+ -+// CHECK: define void @f_fpr_tracking(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, i8 zeroext %i) -+void f_fpr_tracking(float a, float b, float c, float d, float e, float f, -+ float g, float h, uint8_t i) {} -+ -+// Check that fp, fp+fp, and int+fp structs are lowered correctly. These will -+// be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are -+// available the widths are <= XLEN and FLEN, and should be expanded to -+// separate arguments in IR. They are passed by the same rules for returns, -+// but will be lowered to simple two-element structs if necessary (as LLVM IR -+// functions cannot return multiple values). -+ -+// A struct containing just one floating-point real is passed as though it -+// were a standalone floating-point real. -+ -+struct float_s { float f; }; -+ -+// CHECK: define void @f_float_s_arg(float) -+void f_float_s_arg(struct float_s a) {} -+ -+// CHECK: define float @f_ret_float_s() -+struct float_s f_ret_float_s() { -+ return (struct float_s){1.0}; -+} -+ -+// A struct containing a float and any number of zero-width bitfields is -+// passed as though it were a standalone floating-point real. -+ -+struct zbf_float_s { int : 0; float f; }; -+struct zbf_float_zbf_s { int : 0; float f; int : 0; }; -+ -+// CHECK: define void @f_zbf_float_s_arg(float) -+void f_zbf_float_s_arg(struct zbf_float_s a) {} -+ -+// CHECK: define float @f_ret_zbf_float_s() -+struct zbf_float_s f_ret_zbf_float_s() { -+ return (struct zbf_float_s){1.0}; -+} -+ -+// CHECK: define void @f_zbf_float_zbf_s_arg(float) -+void f_zbf_float_zbf_s_arg(struct zbf_float_zbf_s a) {} -+ -+// CHECK: define float @f_ret_zbf_float_zbf_s() -+struct zbf_float_zbf_s f_ret_zbf_float_zbf_s() { -+ return (struct zbf_float_zbf_s){1.0}; -+} -+ -+// Check that structs containing two float values (FLEN <= width) are expanded -+// provided sufficient FPRs are available. -+ -+struct float_float_s { float f; float g; }; -+ -+// CHECK: define void @f_float_float_s_arg(float, float) -+void f_float_float_s_arg(struct float_float_s a) {} -+ -+// CHECK: define { float, float } @f_ret_float_float_s() -+struct float_float_s f_ret_float_float_s() { -+ return (struct float_float_s){1.0, 2.0}; -+} -+ -+// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, i64 %h.coerce) -+void f_float_float_s_arg_insufficient_fprs(float a, float b, float c, float d, -+ float e, float f, float g, struct float_float_s h) {} -+ -+// Check that structs containing int+float values are expanded, provided -+// sufficient FPRs and GPRs are available. The integer components are neither -+// sign or zero-extended. -+ -+struct float_int8_s { float f; int8_t i; }; -+struct float_uint8_s { float f; uint8_t i; }; -+struct float_int32_s { float f; int32_t i; }; -+struct float_int64_s { float f; int64_t i; }; -+struct float_int128bf_s { float f; __int128_t i : 64; }; -+struct float_int8_zbf_s { float f; int8_t i; int : 0; }; -+ -+// CHECK: define void @f_float_int8_s_arg(float, i8) -+void f_float_int8_s_arg(struct float_int8_s a) {} -+ -+// CHECK: define { float, i8 } @f_ret_float_int8_s() -+struct float_int8_s f_ret_float_int8_s() { -+ return (struct float_int8_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_uint8_s_arg(float, i8) -+void f_float_uint8_s_arg(struct float_uint8_s a) {} -+ -+// CHECK: define { float, i8 } @f_ret_float_uint8_s() -+struct float_uint8_s f_ret_float_uint8_s() { -+ return (struct float_uint8_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_int32_s_arg(float, i32) -+void f_float_int32_s_arg(struct float_int32_s a) {} -+ -+// CHECK: define { float, i32 } @f_ret_float_int32_s() -+struct float_int32_s f_ret_float_int32_s() { -+ return (struct float_int32_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_int64_s_arg(float, i64) -+void f_float_int64_s_arg(struct float_int64_s a) {} -+ -+// CHECK: define { float, i64 } @f_ret_float_int64_s() -+struct float_int64_s f_ret_float_int64_s() { -+ return (struct float_int64_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_int128bf_s_arg(float, i64) -+void f_float_int128bf_s_arg(struct float_int128bf_s a) {} -+ -+// CHECK: define <{ float, i64 }> @f_ret_float_int128bf_s() -+struct float_int128bf_s f_ret_float_int128bf_s() { -+ return (struct float_int128bf_s){1.0, 2}; -+} -+ -+// The zero-width bitfield means the struct can't be passed according to the -+// floating point calling convention. -+ -+// CHECK: define void @f_float_int8_zbf_s(float, i8) -+void f_float_int8_zbf_s(struct float_int8_zbf_s a) {} -+ -+// CHECK: define { float, i8 } @f_ret_float_int8_zbf_s() -+struct float_int8_zbf_s f_ret_float_int8_zbf_s() { -+ return (struct float_int8_zbf_s){1.0, 2}; -+} -+ -+// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i64 %i.coerce) -+void f_float_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e, -+ int f, int g, int h, struct float_int8_s i) {} -+ -+// CHECK: define void @f_struct_float_int8_insufficient_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, i64 %i.coerce) -+void f_struct_float_int8_insufficient_fprs(float a, float b, float c, float d, -+ float e, float f, float g, float h, struct float_int8_s i) {} -+ -+// Complex floating-point values or structs containing a single complex -+// floating-point value should be passed as if it were an fp+fp struct. -+ -+// CHECK: define void @f_floatcomplex(float %a.coerce0, float %a.coerce1) -+void f_floatcomplex(float __complex__ a) {} -+ -+// CHECK: define { float, float } @f_ret_floatcomplex() -+float __complex__ f_ret_floatcomplex() { -+ return 1.0; -+} -+ -+struct floatcomplex_s { float __complex__ c; }; -+ -+// CHECK: define void @f_floatcomplex_s_arg(float, float) -+void f_floatcomplex_s_arg(struct floatcomplex_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatcomplex_s() -+struct floatcomplex_s f_ret_floatcomplex_s() { -+ return (struct floatcomplex_s){1.0}; -+} -+ -+// Test single or two-element structs that need flattening. e.g. those -+// containing nested structs, floats in small arrays, zero-length structs etc. -+ -+struct floatarr1_s { float a[1]; }; -+ -+// CHECK: define void @f_floatarr1_s_arg(float) -+void f_floatarr1_s_arg(struct floatarr1_s a) {} -+ -+// CHECK: define float @f_ret_floatarr1_s() -+struct floatarr1_s f_ret_floatarr1_s() { -+ return (struct floatarr1_s){{1.0}}; -+} -+ -+struct floatarr2_s { float a[2]; }; -+ -+// CHECK: define void @f_floatarr2_s_arg(float, float) -+void f_floatarr2_s_arg(struct floatarr2_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_s() -+struct floatarr2_s f_ret_floatarr2_s() { -+ return (struct floatarr2_s){{1.0, 2.0}}; -+} -+ -+struct floatarr2_tricky1_s { struct { float f[1]; } g[2]; }; -+ -+// CHECK: define void @f_floatarr2_tricky1_s_arg(float, float) -+void f_floatarr2_tricky1_s_arg(struct floatarr2_tricky1_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s() -+struct floatarr2_tricky1_s f_ret_floatarr2_tricky1_s() { -+ return (struct floatarr2_tricky1_s){{{{1.0}}, {{2.0}}}}; -+} -+ -+struct floatarr2_tricky2_s { struct {}; struct { float f[1]; } g[2]; }; -+ -+// CHECK: define void @f_floatarr2_tricky2_s_arg(float, float) -+void f_floatarr2_tricky2_s_arg(struct floatarr2_tricky2_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s() -+struct floatarr2_tricky2_s f_ret_floatarr2_tricky2_s() { -+ return (struct floatarr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}}; -+} -+ -+struct floatarr2_tricky3_s { union {}; struct { float f[1]; } g[2]; }; -+ -+// CHECK: define void @f_floatarr2_tricky3_s_arg(float, float) -+void f_floatarr2_tricky3_s_arg(struct floatarr2_tricky3_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_tricky3_s() -+struct floatarr2_tricky3_s f_ret_floatarr2_tricky3_s() { -+ return (struct floatarr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}}; -+} -+ -+struct floatarr2_tricky4_s { union {}; struct { struct {}; float f[1]; } g[2]; }; -+ -+// CHECK: define void @f_floatarr2_tricky4_s_arg(float, float) -+void f_floatarr2_tricky4_s_arg(struct floatarr2_tricky4_s a) {} -+ -+// CHECK: define { float, float } @f_ret_floatarr2_tricky4_s() -+struct floatarr2_tricky4_s f_ret_floatarr2_tricky4_s() { -+ return (struct floatarr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}}; -+} -+ -+// Test structs that should be passed according to the normal integer calling -+// convention. -+ -+struct int_float_int_s { int a; float b; int c; }; -+ -+// CHECK: define void @f_int_float_int_s_arg([2 x i64] %a.coerce) -+void f_int_float_int_s_arg(struct int_float_int_s a) {} -+ -+// CHECK: define [2 x i64] @f_ret_int_float_int_s() -+struct int_float_int_s f_ret_int_float_int_s() { -+ return (struct int_float_int_s){1, 2.0, 3}; -+} -+ -+struct char_char_float_s { char a; char b; float c; }; -+ -+// CHECK-LABEL: define void @f_char_char_float_s_arg(i64 %a.coerce) -+void f_char_char_float_s_arg(struct char_char_float_s a) {} -+ -+// CHECK: define i64 @f_ret_char_char_float_s() -+struct char_char_float_s f_ret_char_char_float_s() { -+ return (struct char_char_float_s){1, 2, 3.0}; -+} -+ -+// Unions are always passed according to the integer calling convention, even -+// if they can only contain a float. -+ -+union float_u { float a; }; -+ -+// CHECK: define void @f_float_u_arg(i64 %a.coerce) -+void f_float_u_arg(union float_u a) {} -+ -+// CHECK: define i64 @f_ret_float_u() -+union float_u f_ret_float_u() { -+ return (union float_u){1.0}; -+} -diff --git a/clang/test/Driver/riscv-abi.c b/clang/test/Driver/riscv-abi.c -index 6a97ff671dd..1a4c7ed477b 100644 ---- a/clang/test/Driver/riscv-abi.c -+++ b/clang/test/Driver/riscv-abi.c -@@ -9,17 +9,15 @@ - - // CHECK-ILP32: "-target-abi" "ilp32" - --// TODO: ilp32f support. --// RUN: not %clang -target riscv32-unknown-elf %s -o %t.o -mabi=ilp32f 2>&1 \ -+// RUN: %clang -target riscv32-unknown-elf %s -### -o %t.o -march=rv32if -mabi=ilp32f 2>&1 \ - // RUN: | FileCheck -check-prefix=CHECK-ILP32F %s - --// CHECK-ILP32F: error: unknown target ABI 'ilp32f' -+// CHECK-ILP32F: "-target-abi" "ilp32f" - --// TODO: ilp32d support. --// RUN: not %clang -target riscv32-unknown-elf %s -o %t.o -mabi=ilp32d 2>&1 \ -+// RUN: %clang -target riscv32-unknown-elf %s -### -o %t.o -march=rv32ifd -mabi=ilp32d 2>&1 \ - // RUN: | FileCheck -check-prefix=CHECK-ILP32D %s - --// CHECK-ILP32D: error: unknown target ABI 'ilp32d' -+// CHECK-ILP32D: "-target-abi" "ilp32d" - - // RUN: not %clang -target riscv32-unknown-elf %s -o %t.o -mabi=lp64 2>&1 \ - // RUN: | FileCheck -check-prefix=CHECK-RV32-LP64 %s -@@ -37,17 +35,15 @@ - - // CHECK-LP64: "-target-abi" "lp64" - --// TODO: lp64f support. --// RUN: not %clang -target riscv64-unknown-elf %s -o %t.o -mabi=lp64f 2>&1 \ -+// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64f -mabi=lp64f 2>&1 \ - // RUN: | FileCheck -check-prefix=CHECK-LP64F %s - --// CHECK-LP64F: error: unknown target ABI 'lp64f' -+// CHECK-LP64F: "-target-abi" "lp64f" - --// TODO: lp64d support. --// RUN: not %clang -target riscv64-unknown-elf %s -o %t.o -mabi=lp64d 2>&1 \ -+// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64d -mabi=lp64d 2>&1 \ - // RUN: | FileCheck -check-prefix=CHECK-LP64D %s - --// CHECK-LP64D: error: unknown target ABI 'lp64d' -+// CHECK-LP64D: "-target-abi" "lp64d" - - // RUN: not %clang -target riscv64-unknown-elf %s -o %t.o -mabi=ilp32 2>&1 \ - // RUN: | FileCheck -check-prefix=CHECK-RV64-ILP32 %s -diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c -index 2c63e0fa29d..36e49c36f03 100644 ---- a/clang/test/Preprocessor/riscv-target-features.c -+++ b/clang/test/Preprocessor/riscv-target-features.c -@@ -47,3 +47,27 @@ - // RUN: %clang -target riscv64-unknown-linux-gnu -march=rv64ic -x c -E -dM %s \ - // RUN: -o - | FileCheck --check-prefix=CHECK-C-EXT %s - // CHECK-C-EXT: __riscv_compressed 1 -+ -+// RUN: %clang -target riscv32-unknown-linux-gnu -march=rv32ifd -x c -E -dM %s \ -+// RUN: -o - | FileCheck --check-prefix=CHECK-SOFT %s -+// RUN: %clang -target riscv64-unknown-linux-gnu -march=rv64ifd -x c -E -dM %s \ -+// RUN: -o - | FileCheck --check-prefix=CHECK-SOFT %s -+// CHECK-SOFT: __riscv_float_abi_soft 1 -+// CHECK-SOFT-NOT: __riscv_float_abi_single -+// CHECK-SOFT-NOT: __riscv_float_abi_double -+ -+// RUN: %clang -target riscv32-unknown-linux-gnu -march=rv32ifd -mabi=ilp32f -x c -E -dM %s \ -+// RUN: -o - | FileCheck --check-prefix=CHECK-SINGLE %s -+// RUN: %clang -target riscv64-unknown-linux-gnu -march=rv64ifd -mabi=lp64f -x c -E -dM %s \ -+// RUN: -o - | FileCheck --check-prefix=CHECK-SINGLE %s -+// CHECK-SINGLE: __riscv_float_abi_single 1 -+// CHECK-SINGLE-NOT: __riscv_float_abi_soft -+// CHECK-SINGLE-NOT: __riscv_float_abi_double -+ -+// RUN: %clang -target riscv32-unknown-linux-gnu -march=rv32ifd -mabi=ilp32d -x c -E -dM %s \ -+// RUN: -o - | FileCheck --check-prefix=CHECK-DOUBLE %s -+// RUN: %clang -target riscv64-unknown-linux-gnu -march=rv64ifd -mabi=lp64d -x c -E -dM %s \ -+// RUN: -o - | FileCheck --check-prefix=CHECK-DOUBLE %s -+// CHECK-DOUBLE: __riscv_float_abi_double 1 -+// CHECK-DOUBLE-NOT: __riscv_float_abi_soft -+// CHECK-DOUBLE-NOT: __riscv_float_abi_single diff --git a/debian/patches/clang-riscv64-multiarch.diff b/debian/patches/risc/clang-riscv64-multiarch.diff similarity index 100% rename from debian/patches/clang-riscv64-multiarch.diff rename to debian/patches/risc/clang-riscv64-multiarch.diff diff --git a/debian/rules b/debian/rules index e236d3ce..2c7280aa 100755 --- a/debian/rules +++ b/debian/rules @@ -365,8 +365,14 @@ override_dh_auto_configure: preconfigure -DLLVM_ENABLE_SPHINX=ON \ -DLLVM_ENABLE_RTTI=ON \ -DLLVM_ENABLE_FFI=ON \ - -DLLVM_LINK_LLVM_DYLIB=ON \ - -DLLVM_BUILD_LLVM_DYLIB=ON \ + -DLLVM_ENABLE_DUMP=ON \ + $(CMAKE_EXTRA) \ + -DLIBCLANG_LIBRARY_VERSION=$(SONAME_EXT) \ + -DCLANG_LINK_CLANG_DYLIB=ON \ + -DENABLE_LINKER_BUILD_ID=ON \ + -DPOLLY_BUNDLED_JSONCPP=OFF \ + -DCOMPILER_RT_USE_LIBCXX=NO \ + $(Z3_FLAG) \ -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="AVR" \ -DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=ON \ -DLIBCLANG_LIBRARY_VERSION=$(SONAME_EXT) \ @@ -381,10 +387,11 @@ override_dh_auto_configure: preconfigure -DSPHINX_WARNINGS_AS_ERRORS=OFF \ -DBOOTSTRAP_CMAKE_CXX_FLAGS='$(BOOTSTRAP_CXXFLAGS_EXTRA)' \ -DBOOTSTRAP_CMAKE_C_FLAGS='$(BOOTSTRAP_CFLAGS_EXTRA)' \ - $(Z3_FLAG) \ - $(CMAKE_EXTRA) \ -DCLANG_BOOTSTRAP_PASSTHROUGH="CMAKE_INSTALL_PREFIX;CMAKE_VERBOSE_MAKEFILE;CMAKE_BUILD_TYPE;CMAKE_CXX_FLAGS_RELWITHDEBINFO;LLVM_LINK_LLVM_DYLIB;LLVM_INSTALL_UTILS;LLVM_VERSION_SUFFIX;LLVM_ENABLE_SPHINX;SPHINX_WARNINGS_AS_ERRORS;LLVM_BUILD_LLVM_DYLIB;LLVM_ENABLE_RTTI;LLVM_ENABLE_FFI;LIBCLANG_LIBRARY_VERSION;ENABLE_LINKER_BUILD_ID;POLLY_BUNDLED_JSONCPP;LLVM_EXPERIMENTAL_TARGETS_TO_BUILD;LLVM_USE_PERF;LLVM_ENABLE_ASSERTIONS;LLVM_BINUTILS_INCDIR;LLVM_HOST_TRIPLE;LLVM_COMPILER_CHECKED;COMPILER_RT_BUILD_BUILTINS;LIBOMP_LIBFLAGS;CMAKE_SHARED_LINKER_FLAGS;PYTHON_EXECUTABLE;LLVM_ENABLE_Z3_SOLVER;LLVM_POLLY_LINK_INTO_TOOLS" - + FOUND_VERSION=`grep LLVM_VERSION_STRING build-llvm/include/llvm/Config/llvm-config.h|cut -d\" -f2`; \ + if ! echo "$(LLVM_VERSION_FULL)"|grep "$$FOUND_VERSION"; then \ + echo "mistmatch of version. Found: $$FOUND_VERSION / Expected: $(LLVM_VERSION_FULL)"; \ + fi # make VERBOSE=VERBOSE=1 diff --git a/debian/unpack.sh b/debian/unpack.sh index f6c0a5a0..47619ee9 100644 --- a/debian/unpack.sh +++ b/debian/unpack.sh @@ -15,5 +15,13 @@ echo "unpack of $LLVM_ARCHIVE" tar Jxf $LLVM_ARCHIVE cd llvm-toolchain-${ORIG_VERSION}_$MAJOR_VERSION~+$VERSION/ +VER_FOUND=$(grep "PACKAGE_VERSION " libcxx/CMakeLists.txt|awk '{print $2}'|cut -d\) -f1) +if test "${MAJOR_VERSION}.0.0" != "$VER_FOUND"; then + echo "Mismatch of version" + echo "Expected $MAJOR_VERSION / Found $VER_FOUND" + echo "Update unpack.sh" + exit 1 +fi + cp -R ../$ORIG_VERSION/debian . QUILT_PATCHES=debian/patches/ quilt push -a --fuzz=0