const Type *Base = 0;
uint64_t NumMembers;
- if (isHomogeneousAggregate(Ty, Base, Ctx, &NumMembers) && NumMembers > 1) {
+ bool IsHFA = isHomogeneousAggregate(Ty, Base, Ctx, &NumMembers);
+ if (IsHFA && NumMembers > 1) {
// Homogeneous aggregates passed in registers will have their elements split
// and stored 16-bytes apart regardless of size (they're notionally in qN,
// qN+1, ...). We reload and store into a temporary local variable
} else {
// Otherwise the object is contiguous in memory
unsigned BeAlign = reg_top_index == 2 ? 16 : 8;
- if (CGF.CGM.getDataLayout().isBigEndian() && !isAggregateTypeForABI(Ty) &&
+ if (CGF.CGM.getDataLayout().isBigEndian() &&
+ (IsHFA || !isAggregateTypeForABI(Ty)) &&
Ctx.getTypeSize(Ty) < (BeAlign * 8)) {
int Offset = BeAlign - Ctx.getTypeSize(Ty) / 8;
BaseAddr = CGF.Builder.CreatePtrToInt(BaseAddr, CGF.Int64Ty);
--- /dev/null
+// RUN: %clang_cc1 -triple arm64_be-linux-gnu -ffreestanding -emit-llvm -O0 -o - %s | FileCheck %s
+
+#include <stdarg.h>
+
+// A single member HFA must be aligned just like a non-HFA register argument.
+double callee(int a, ...) {
+// CHECK: %align_be = add i64 %{{.*}}, 8
+ va_list vl;
+ va_start(vl, a);
+ double result = va_arg(vl, struct { double a; }).a;
+ va_end(vl);
+ return result;
+}