diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -5418,7 +5418,8 @@ bool isDarwinPCS() const { return Kind == DarwinPCS; } ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic) const; - ABIArgInfo classifyArgumentType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy, bool IsVariadic, + unsigned CallingConvention) const; ABIArgInfo coerceIllegalVector(QualType Ty) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, @@ -5432,7 +5433,8 @@ classifyReturnType(FI.getReturnType(), FI.isVariadic()); for (auto &it : FI.arguments()) - it.info = classifyArgumentType(it.type); + it.info = classifyArgumentType(it.type, FI.isVariadic(), + FI.getCallingConvention()); } Address EmitDarwinVAArg(Address VAListAddr, QualType Ty, @@ -5635,7 +5637,9 @@ return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } -ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { +ABIArgInfo +AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, + unsigned CallingConvention) const { Ty = useFirstFieldIfTransparentUnion(Ty); // Handle illegal vector types here. @@ -5681,7 +5685,11 @@ // Homogeneous Floating-point Aggregates (HFAs) need to be expanded. const Type *Base = nullptr; uint64_t Members = 0; - if (isHomogeneousAggregate(Ty, Base, Members)) { + bool IsWin64 = Kind == Win64 || CallingConvention == llvm::CallingConv::Win64; + bool IsWinVariadic = IsWin64 && IsVariadic; + // In variadic functions on Windows, all composite types are treated alike, + // no special handling of HFAs/HVAs. + if (!IsWinVariadic && isHomogeneousAggregate(Ty, Base, Members)) { return ABIArgInfo::getDirect( llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members)); } @@ -5838,10 +5846,10 @@ return Members <= 4; } -Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, - QualType Ty, - CodeGenFunction &CGF) const { - ABIArgInfo AI = classifyArgumentType(Ty); +Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + ABIArgInfo AI = classifyArgumentType(Ty, /*IsVariadic=*/true, + CGF.CurFnInfo->getCallingConvention()); bool IsIndirect = AI.isIndirect(); llvm::Type *BaseTy = CGF.ConvertType(Ty); diff --git a/clang/test/CodeGen/ms_abi_aarch64.c b/clang/test/CodeGen/ms_abi_aarch64.c --- a/clang/test/CodeGen/ms_abi_aarch64.c +++ b/clang/test/CodeGen/ms_abi_aarch64.c @@ -84,3 +84,39 @@ __builtin_va_end(ap); // WIN64: call void @llvm.va_end } + +struct HFA { + float a, b, c; +}; + +__attribute__((ms_abi)) void msabi_hfa(struct HFA a); +__attribute__((ms_abi)) void msabi_hfa_vararg(struct HFA a, int b, ...); + +void call_msabi_hfa(void) { + // COMMON-LABEL: define{{.*}} void @call_msabi_hfa() + // WIN64: call void @msabi_hfa([3 x float] {{.*}}) + // LINUX: call win64cc void @msabi_hfa([3 x float] {{.*}}) + msabi_hfa((struct HFA){1.0f, 2.0f, 3.0f}); +} + +void call_msabi_hfa_vararg(void) { + // COMMON-LABEL: define{{.*}} void @call_msabi_hfa_vararg() + // WIN64: call void ([2 x i64], i32, ...) @msabi_hfa_vararg([2 x i64] {{.*}}, i32 4, [2 x i64] {{.*}}) + // LINUX: call win64cc void ([2 x i64], i32, ...) @msabi_hfa_vararg([2 x i64] {{.*}}, i32 4, [2 x i64] {{.*}}) + msabi_hfa_vararg((struct HFA){1.0f, 2.0f, 3.0f}, 4, + (struct HFA){5.0f, 6.0f, 7.0f}); +} + +__attribute__((ms_abi)) void get_msabi_hfa_vararg(int a, ...) { + // COMMON-LABEL: define{{.*}} void @get_msabi_hfa_vararg + __builtin_ms_va_list ap; + __builtin_ms_va_start(ap, a); + // COMMON: %[[AP:.*]] = alloca i8* + // COMMON: call void @llvm.va_start + struct HFA b = __builtin_va_arg(ap, struct HFA); + // COMMON: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]] + // COMMON-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 16 + // COMMON-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]] + // COMMON-NEXT: bitcast i8* %[[AP_CUR]] to %struct.HFA* + __builtin_ms_va_end(ap); +}