[clang] [AArch64] Fix handling of HFAs passed to Windows variadic functions
The documentation says that for variadic functions, all composites
are treated similarly, no special handling of HFAs/HVAs, not even
for the fixed arguments of a variadic function.
Differential Revision: https://reviews.llvm.org/D100467
GitOrigin-RevId: 8e0f2e89ff951c74875ed751e2215cc263b33328
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 3ff3eed..bd3c265 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/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/test/CodeGen/ms_abi_aarch64.c b/test/CodeGen/ms_abi_aarch64.c
index 8526ce9..cf24442 100644
--- a/test/CodeGen/ms_abi_aarch64.c
+++ b/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);
+}